1.前言
C#打印小票可以與普通打印機一樣,調用PrintDocument實現。也可以發送標注你的ESC指令實現。由於 調用PrintDocument類時,無法操作使用串口或TCP/IP接口連接的pos打印機,並且無法發送控制指令實現pos打印機的切紙、走紙等動作。因此個人建議使用ESC指令進行打印會更通用。
本類需要調用 ImageProcessor.cs
2.POS機打印小票ReceiptHelper
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Drawing;
using System.Management;
using System.IO;
using LaisonTech.MediaLib;
using LaisonTech.CommonBLL;
using Microsoft.Win32.SafeHandles;
namespace LaisonTech.MediaLib
{
#region 結構體定義
[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
int Internal;
int InternalHigh;
int Offset;
int OffSetHigh;
int hEvent;
};
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
/// <summary>
/// 對齊方式
/// </summary>
public enum eTextAlignMode
{
Left = 0,
Middle = 1,
Right = 2
}
#endregion
/// <summary>
/// 小票打印類
/// 使用方法:
/// 1 GetPrinterList獲取已經安裝的所有打印機列表.
/// Open 打開指定打印機
/// 2 控制打印機動作、執行打印內容之前,必須先調用StartPrint,准備向打印機發送控制指令
/// 3 調用SetLeft, SetBold, SetAlignMode, SetFontSize ... ...設置打印參數
/// 4 PrintText 打印內容.注意:打印該行內容后會自動換行(本類會在該行內容末尾添加一個換行符)
/// PrintImageFile 或 PrintBitMap打印圖片
/// 5 控制指令和打印內容都發送完畢后,調用 EndPrint執行真正打印動作
/// 6 退出程序前調用Close
/// </summary>
public class ReceiptHelper
{
#region 指令定義
private static Byte[] Const_Init = new byte[] { 0x1B, 0x40,
0x20, 0x20, 0x20, 0x0A,
0x1B, 0x64,0x10};
//設置左邊距
private const string Const_SetLeft = "1D 4C ";
//設置粗體
private const string Const_SetBold = "1B 45 ";
private const String Const_Bold_YES = "01";
private const String Const_Bold_NO = "00";
//設置對齊方式
private const string Const_SetAlign = "1B 61 ";
private const String Const_Align_Left = "30";
private const String Const_Align_Middle = "31";
private const String Const_Align_Right = "32";
//設置字體大小,與 SetBigFont 不能同時使用
private const string Const_SetFontSize = "1D 21 ";
//設置是否大字體,等同於 SetFontSize = 2
//private const String Const_SetBigFontBold = "1B 21 38";
//private const String Const_SetBigFontNotBold = "1B 21 30";
//private const String Const_SetCancelBigFont = "1B 21 00";
/// <summary>
/// 打印並走紙
/// </summary>
private static Byte[] Const_Cmd_Print = new byte[] { 0x1B, 0x4A, 0x00 };
//走紙
private const string Const_FeedForward = "1B 4A ";
private const string Const_FeedBack = "1B 6A ";
//切紙
private static Byte[] Const_SetCut = new byte[] { 0x1D, 0x56, 0x30};
//查詢打印機狀態
private static Byte[] Const_QueryID = new byte[] { 0x1D, 0x67, 0x61};
//回復幀以 ID 開頭
private static String Const_ResponseQueryID = "ID";
/// <summary>
/// 設置圖標的指令
/// </summary>
private static Byte[] Const_SetImageCommand = new Byte[] { 0x1B, 0x2A, 0x21 };
#endregion
#region 常量定義
/// <summary>
/// 最大字體大小
/// </summary>
public const Int32 Const_MaxFontSize = 8;
/// <summary>
/// 最大走紙距離
/// </summary>
public const Int32 Const_MaxFeedLength = 5000;
/// <summary>
/// 最大高寬
/// </summary>
public const Int32 Const_MaxImageLength = 480;
/// <summary>
/// 每次通信最多打印的行數
/// </summary>
public const Int32 Const_OncePrintRowCount = 24;
public const Int32 Const_BrightnessGate = 100;
/// <summary>
/// 無效句柄
/// </summary>
public const Int32 Const_InvalidHandle = -1;
#endregion
#region 私有成員
/// <summary>
/// 打印機句柄
/// </summary>
private int m_Handle = -1;
/// <summary>
/// 是否已經初始化
/// </summary>
private Boolean m_Inited = false;
#endregion
#region 私有函數
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out Int32 hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(Int32 hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(Int32 hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(Int32 hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(Int32 hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(Int32 hPrinter, Byte[] pBytes, Int32 dwCount, out Int32 dwWritten);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(Int32 hPrinter);
/// <summary>
/// 發送指令
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
private Boolean SendCommand(Byte[] cmd)
{
if (m_Handle == Const_InvalidHandle || cmd == null || cmd.Length < 2)
{
return false;
}
int writelen = 0;
Boolean bl = WritePrinter(m_Handle, cmd, cmd.Length, out writelen);
if (!bl) return false;
return (writelen >= cmd.Length);
}
/// <summary>
/// 發送文本格式的指令
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
private Boolean SendCommand(String hexstrcmd)
{
if (m_Handle == Const_InvalidHandle || hexstrcmd == null || hexstrcmd.Length < 4)
{
return false;
}
byte[] mybyte = null;
Boolean bl = DataFormatProcessor.HexStringToBytes(hexstrcmd, out mybyte);
bl = SendCommand(mybyte);
return bl;
}
#endregion
#region 內部處理 - 打印圖片
/// <summary>
/// 把圖片轉換為指令字節,圖片最大高寬不能超過480
/// </summary>
/// <param name="image"></param>
/// <param name="bmpbytes"></param>
/// <returns></returns>
public static Boolean LoadImage(Bitmap image,
ref Byte[] bitarray,ref Int32 datawidth,ref Int32 dataheight)
{
Int32 newwidth = 0;
Int32 newheight = 0;
Bitmap destimage = image;
Boolean bl = false;
//如果高度超過范圍,或寬度超過范圍,需要進行縮小
if (image.Width > Const_MaxImageLength || image.Height > Const_MaxImageLength)
{
//按照高度和寬度,較大的那一邊,進行縮放
if (image.Width > image.Height)
{
newwidth = Const_MaxImageLength;
newheight = (Int32)(image.Height * newwidth / (float)image.Width);
}
else
{
newheight = Const_MaxImageLength;
newwidth = (Int32)(newheight * image.Width / (float)image.Height);
}
bl = ImageProcessor.ResizeImage(image, newwidth, newheight, ref destimage);
}
//把數據轉換為字節數組
bl = GetBitArray(image, ref bitarray, ref datawidth, ref dataheight);
return bl;
}
/// <summary>
/// 把圖片轉換為指令字節,圖片最大高寬不能超過480
/// 如果圖片的高度不是24的整數倍,則修改為24的整數倍
/// </summary>
/// <param name="image"></param>
/// <param name="bmpbytes"></param>
/// <returns></returns>
public static Boolean LoadImageFromFile(String imagefilename, ref Byte[] bmpbytes,
ref Int32 width, ref Int32 height)
{
Bitmap img = ImageProcessor.LoadBitImage(imagefilename);
if (img == null)
{
return false;
}
Boolean bl = LoadImage(img, ref bmpbytes, ref width, ref height);
return bl;
}
/// <summary>
/// 把圖片轉換為位圖數組,每個字節的每個比特位,對應當前像素 是否需要打印
/// </summary>
/// <param name="img"></param>
/// <param name="allbitary"></param>
/// <returns></returns>
public static Boolean GetBitArray(Bitmap img,
ref Byte[] allbitary, ref Int32 width, ref Int32 height)
{
if (img == null)
{
return false;
}
//ESC指令格式規定:
//1 打印圖片時,每條指令最多只打印24行;不足24行的,也要用全0填充滿數據字節
//2 打印24行數據時,按照光柵模式縱向獲取數據
// 即先獲取所有x=0的點(第0列)轉換為3個字節;
// 再獲取所有x=1的點轉換為3個字節;...直到獲取到最右側一列的點
//3 打印完當前24行數據后,再獲取后續24行的數據內容,直到所有的數據獲取完畢
//獲取亮度數組
Boolean[] briary = null;
Boolean bl = ImageProcessor.ToBooleanArray(img, Const_BrightnessGate, ref briary);
if (!bl)
{
return false;
}
height = img.Height;//如果圖像高度不是24整數倍,設置為24的整數倍
if (height % Const_OncePrintRowCount != 0)
{
height = height + Const_OncePrintRowCount - height % Const_OncePrintRowCount;
}
width = img.Width;//如果圖像寬度不是8的整數倍,設置為8的整數倍
if (width % 8 != 0)
{
width = width + 8 - width % 8;
}
Int32 bytelen = height * width / 8;//每個像素對應1個比特位,因此總字節數=像素位數/8
allbitary = new Byte[bytelen];
Int32 byteidxInCol = 0;//當前列里首個像素,在目標字節數組里的下標
Int32 byteidx = 0;//當前像素在目標數組里的字節下標
Int32 bitidx = 0;//當前像素在目標數組里當前字節里的比特位下標
Int32 pixidxInCol = 0;//當前像素在當前列里的第幾個位置
Int32 pixidx = 0;//當前像素在原始圖片里的下標
Int32 rowidx = 0; //當前 處理的像素點所在行,不能超過 圖像高度
Int32 curprocrows = 0;//當前需要處理的行數量
while (rowidx < height)
{
//按照縱向次序,把當前列的24個數據,轉換為3個字節
for (Int32 colidx = 0; colidx < img.Width; ++colidx)
{
//如果當前還剩余超過24行沒處理,處理24行
if (rowidx + Const_OncePrintRowCount <= img.Height)
{
curprocrows = Const_OncePrintRowCount;
}
else
{
//已經不足24行,只處理剩余行數
curprocrows = img.Height - rowidx;
}
pixidxInCol = 0; //本列里從像素0開始處理
for (Int32 y = rowidx; y < rowidx + curprocrows; ++y)
{
//原始圖片里像素位置
pixidx = y * img.Width + colidx;
//獲取當前像素的亮度值.如果當前像素是黑點,需要把數組里的對應比特位設置為1
if (briary[pixidx])
{
bitidx = 7 - pixidxInCol % 8;//最高比特位對應首個像素.最低比特位對應末個像素
byteidx = byteidxInCol + pixidxInCol / 8; //由於最后一段可能不足24行,因此不能使用byteidx++
DataFormatProcessor.SetBitValue(bitidx, true, ref allbitary[byteidx]);
}
pixidxInCol++;
}
byteidxInCol += 3;//每列固定24個像素,3個字節
}
rowidx += Const_OncePrintRowCount;
}
return true;
}
#endregion
#region 公開函數
private static ReceiptHelper m_instance = new ReceiptHelper();
/// <summary>
/// 當前使用的打印機名稱
/// </summary>
public String PrinterName
{
get;private set;
}
/// <summary>
/// 單件模式
/// </summary>
/// <returns></returns>
public static ReceiptHelper GetInstance()
{
return m_instance;
}
/// <summary>
/// 獲取本機安裝的所有打印機
/// </summary>
/// <returns></returns>
public static List<String> GetPrinterList()
{
List<String> ret = new List<String>();
if (PrinterSettings.InstalledPrinters.Count < 1)
{
return ret;
}
foreach (String printername in PrinterSettings.InstalledPrinters)
{
ret.Add(printername);
}
return ret;
}
/// <summary>
/// 打開打印機
/// </summary>
/// <param name="printername"></param>
/// <returns></returns>
public Boolean Open(String printername)
{
if (m_Inited)
{
return true;
}
Boolean bl = OpenPrinter(printername.Normalize(), out m_Handle, IntPtr.Zero);
m_Inited = (bl && m_Handle != 0);
return true;
}
/// <summary>
/// 開始打印,在打印之前必須調用此函數
/// </summary>
/// <returns></returns>
public Boolean StartPrint()
{
if (!m_Inited)
{
return false;
}
DOCINFOA di = new DOCINFOA();
di.pDocName = "My C#.NET RAW Document";
di.pDataType = "RAW";
//Start a document.
Boolean bl = StartDocPrinter(m_Handle, 1, di);
if (!bl)
{
return false;
}
// Start a page.
bl = StartPagePrinter(m_Handle);
return bl;
}
/// <summary>
/// 結束打印,在打印結束之后必須調用此函數
/// </summary>
/// <returns></returns>
public Boolean EndPrint()
{
if (!m_Inited)
{
return false;
}
Boolean bl = EndPagePrinter(m_Handle);
bl = EndDocPrinter(m_Handle);
return bl;
}
/// <summary>
/// 銷毀
/// </summary>
/// <returns></returns>
public Boolean Close()
{
if (!m_Inited)
{
return true;
}
m_Inited = false;
//關閉設備句柄
ClosePrinter(m_Handle);
m_Handle = -1;
return true;
}
/// <summary>
/// 打印文本.在調用本函數之前必須先調用正確的 設置字體、左邊距
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public Boolean PrintText(String content)
{
if (!m_Inited)
{
return false;
}
byte[] bytes = null;
if (content.Length < 1)
{
content = " ";
}
if (content[content.Length - 1] != (char)0x0D &&
content[content.Length - 1] != (char)0x0A)
{
content = content + (char)0x0A;
}
bytes = DataFormatProcessor.StringToBytes(content);
bool bl = SendCommand(bytes);
return bl;
}
/// <summary>
/// 設置對齊方式
/// </summary>
/// <param name="left"></param>
/// <returns></returns>
public bool SetAlignMode(eTextAlignMode alignmode)
{
if (!m_Inited)
{
return false;
}
String code = String.Empty;
switch (alignmode)
{
case eTextAlignMode.Left:
code = Const_Align_Left;
break;
case eTextAlignMode.Middle:
code = Const_Align_Middle;
break;
case eTextAlignMode.Right:
code = Const_Align_Right;
break;
default:
code = Const_Align_Left;
break;
}
//注意:先低字節后高字節
string str = Const_SetAlign + code;
bool bl = SendCommand(str);
return bl;
}
/// <summary>
/// 設置左邊距
/// </summary>
/// <param name="left"></param>
/// <returns></returns>
public bool SetLeft(int left)
{
if (!m_Inited)
{
return false;
}
//注意:先低字節后高字節
String hexstr = left.ToString("X4");
string str = Const_SetLeft + hexstr.Substring(2, 2) + hexstr.Substring(0, 2);
bool bl = SendCommand(str);
return bl;
}
/// <summary>
/// 設置粗體
/// </summary>
/// <param name="bold"></param>
/// <returns></returns>
public Boolean SetBold(Boolean bold)
{
if (!m_Inited)
{
return false;
}
//注意:先低字節后高字節
String str = String.Empty;
if (bold)
{
str = Const_SetBold + Const_Bold_YES;
}
else
{
str = Const_SetBold + Const_Bold_NO;
}
bool bl = SendCommand(str);
return bl;
}
/// <summary>
/// 切紙
/// </summary>
/// <returns></returns>
public bool Cut()
{
if (!m_Inited)
{
return false;
}
bool bl = SendCommand(Const_SetCut);
return bl;
}
/// <summary>
/// 打印圖片
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public bool PrintImageFile(String imgfilename)
{
if (!m_Inited)
{
return false;
}
Bitmap img = ImageProcessor.LoadBitImage(imgfilename);
if (img == null)
{
return false;
}
Boolean bl = PrintBitmap(img);
return bl;
}
/// <summary>
/// 打印圖片
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public bool PrintBitmap(Bitmap bitmap)
{
if (!m_Inited)
{
return false;
}
if (bitmap == null ||
bitmap.Width > Const_MaxImageLength ||
bitmap.Height > Const_MaxImageLength)
{
return false;
}
Byte[] bitary = null;
Int32 width = 0;
Int32 height = 0;
Boolean bl = GetBitArray(bitmap, ref bitary, ref width, ref height);
bl = PrintBitmapBytes(bitary, bitmap.Width, bitmap.Height);
return bl;
}
/// <summary>
/// 打印圖片
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public bool PrintBitmapBytes(Byte[] imgbitarray, Int32 width, Int32 height)
{
if (!m_Inited)
{
return false;
}
Int32 bytes = width * height / 8;
//檢查是否尺寸符合要求
if (width > Const_MaxImageLength || height > Const_MaxFeedLength ||
width < 1 || height < 1 ||
imgbitarray == null)
{
return false;
}
//每次獲取24行的數據進行發送,這24行的字節數
Int32 blockbytes = width * Const_OncePrintRowCount / 8;
if (blockbytes < 1)
{
return false;
}
Boolean bl = false;
//一共需要發送的塊數量
Int32 blocks = imgbitarray.Length / blockbytes;
//每次發送的數據字節數 = 1B 2A 21 2字節長度 + 數據內容
Byte[] cmdbytes = new Byte[5 + blockbytes];
//指令
Array.Copy(Const_SetImageCommand, cmdbytes, 3);
//數據長度,即 每行的點數
DataFormatProcessor.Int16ToBytes(width, ref cmdbytes, 3);
//數據內容
for (Int32 blockidx = 0; blockidx < blocks; ++blockidx)
{
Array.Copy(imgbitarray, blockidx * blockbytes, cmdbytes, 5, blockbytes);
//發送當前指令
bl = SendCommand(cmdbytes);
if (!bl) return false;
//休眠20毫秒
Thread.Sleep(20);
//發送 打印指令
bl = SendCommand(Const_Cmd_Print);
if (!bl) return false;
}
return bl;
}
/// <summary>
/// 走紙
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public bool Feed(int length)
{
if (!m_Inited)
{
return false;
}
if (length < 1)
length = 1;
if (length > Const_MaxFeedLength)
{
length = Const_MaxFeedLength;
}
string len = length.ToString("X2");
len = Const_FeedForward + len;
bool bl = SendCommand(len);
return bl;
}
/// <summary>
/// 回退走紙
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public bool FeedBack(int length)
{
if (!m_Inited)
{
return false;
}
if (length < 1)
length = 1;
if (length > Const_MaxFeedLength)
{
length = Const_MaxFeedLength;
}
string len = length.ToString("X2");
len = Const_FeedBack + len;
bool bl = SendCommand(len);
return bl;
}
/// <summary>
/// 設置字體大小.本函數不可與SetBigFont同時使用
/// </summary>
/// <param name="sizerate">大小倍率,取值范圍 1 - 8</param>
/// <returns></returns>
public bool SetFontSize(Int32 sizerate)
{
if (!m_Inited)
{
return false;
}
if (sizerate < 1)
{
sizerate = 1;
}
if (sizerate > Const_MaxFontSize)
{
sizerate = Const_MaxFontSize;
}
sizerate--;
String sizecodestr = Const_SetFontSize + sizerate.ToString("X1") + sizerate.ToString("X1");
bool bl = SendCommand(sizecodestr);
return bl;
}
#endregion
}
}
3.圖像處理 ImageProcessor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using LaisonTech.CommonBLL;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using AForge.Imaging.Filters;
namespace LaisonTech.MediaLib
{
/// <summary>
/// 圖片格式
/// </summary>
public enum ePictureFileFormat
{
Bmp = 0,
Gif = 1,
Icon = 2,
Jpeg = 3,
Png = 4,
}
/// <summary>
/// 轉為灰度圖像的方式
/// </summary>
public enum eGrayMode
{
/// <summary>
/// 算數平均
/// </summary>
ArithmeticAverage = 0,
/// <summary>
/// 加權平均
/// </summary>
WeightedAverage = 1,
}
/// <summary>
/// 比較2個圖片的指定區域范圍,像素的相同類型
/// </summary>
public enum eAreaDifferentType
{
/// <summary>
/// 所有像素都相同
/// </summary>
AllSame = 0,
/// <summary>
/// 所有像素都不同
/// </summary>
AllDifferent = 1,
/// <summary>
/// 部分相同部分不同
/// </summary>
Partial = 2,
}
/// <summary>
/// 圖片文件處理
/// </summary>
public class ImageProcessor
{
#region 常量定義
public const Byte Const_BrightnessWhite = 255;
public const Byte Const_BrightnessBlack = 0;
/// <summary>
/// 比較結果的圖片里,亮度相同部分的填充顏色
/// </summary>
public static Color Const_SameBrightnessColor = Color.Black;
/// <summary>
/// 比較結果的圖片里,亮度相同部分的填充顏色
/// </summary>
public static Color Const_DifferentBrightnessColor = Color.White;
public const Byte Const_BlackBrightness = 0;
public const Byte Const_WhiteBrightness = 255;
public const Int32 Const_MaxBrightness = 255;
public const Int32 Const_MinBrightness = -255;
/// <summary>
/// 亮度的中間值
/// </summary>
public const Int32 Const_MiddleBrightness = 128;
#endregion
#region 屏幕截圖,打印
/// <summary>
/// 獲取屏幕分辨率
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
public static void GetScreenSize(ref Int32 width, ref Int32 height)
{
height = Screen.PrimaryScreen.Bounds.Height;
width = Screen.PrimaryScreen.Bounds.Width;
}
/// <summary>
///截圖指定控件上顯示的內容
/// </summary>
/// <param name="ctrl"></param>
/// <returns></returns>
public static Image CaptureControlImage(Control ctrl)
{
if (ctrl == null)
{
return null;
}
Control parent = ctrl;
if (ctrl.Parent != null)
{
parent = ctrl.Parent;
}
Point screenPoint = parent.PointToScreen(ctrl.Location);
Image ret = new Bitmap(ctrl.Width, ctrl.Height);
Graphics g = Graphics.FromImage(ret);
g.CopyFromScreen(screenPoint.X, screenPoint.Y,
0, 0, ctrl.Size);
g.DrawImage(ret, 0, 0);
return ret;
}
#endregion
#region 裝載圖片
/// <summary>
/// 裝載圖像文件
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static Image LoadImage(String filename)
{
//Boolean bl = FileProcessor.FileExist(filename);
//if (!bl)
//{
// return null;
//}
//Bitmap image = (Bitmap)Bitmap.FromFile(filename);
//return image;
//以上方法會導致圖片文件被鎖定,無法刪除移動
Byte[] photodata = null;
Boolean bl = FileProcessor.FileExist(filename);
if (!bl)
{
return null;
}
bl = FileProcessor.ReadFileBytes(filename, out photodata);
if (!bl)
{
return null;
}
MemoryStream ms = null;
Image myImage = null;
try
{
ms = new MemoryStream(photodata);
myImage = Bitmap.FromStream(ms);
ms.Close();
}
catch (System.Exception ex)
{
Console.WriteLine("LoadImage error:" + ex.Message);
myImage = null;
}
return myImage;
}
/// <summary>
/// 裝載圖像文件
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static Bitmap LoadBitImage(String filename)
{
Bitmap ret = (Bitmap)LoadImage(filename);
return ret;
}
/// <summary>
/// 保存圖片到指定路徑
/// </summary>
/// <param name="img"></param>
/// <param name="filename"></param>
/// <returns></returns>
public static Boolean SaveImage(Image img, String filename)
{
FileProcessor.DeleteFile(filename);
if (img == null)
{
return false;
}
//獲取保存圖片的路徑,如果路徑不存在,新建
String folder = FileProcessor.GetDirectoryName(filename);
if (!FileProcessor.DirectoryExist(folder))
{
FileProcessor.CreateDirectory(folder);
}
img.Save(filename);
Boolean bl = FileProcessor.FileExist(filename);
return bl;
}
#endregion
#region 轉換圖片格式
/// <summary>
/// 轉換圖片格式
/// </summary>
/// <param name="bmpfilename"></param>
/// <param name="jpgfilename"></param>
/// <returns></returns>
public static Boolean BmpToJpg(String bmpfilename, String jpgfilename)
{
Boolean bl = ChangeFileFormat(bmpfilename, jpgfilename, ePictureFileFormat.Jpeg);
return bl;
}
/// <summary>
/// 轉換圖片格式
/// </summary>
/// <param name="srcfilename"></param>
/// <param name="destfilename"></param>
/// <param name="destformat"></param>
/// <returns></returns>
public static Boolean ChangeFileFormat(String srcfilename, String destfilename, ePictureFileFormat destformat)
{
Boolean bl = FileProcessor.FileExist(srcfilename);
if (!bl)
{
return false;
}
Image image = Image.FromFile(srcfilename);
ImageFormat IFMT = null;
switch (destformat)
{
case ePictureFileFormat.Bmp:
IFMT = ImageFormat.Bmp;
break;
case ePictureFileFormat.Gif:
IFMT = ImageFormat.Gif;
break;
case ePictureFileFormat.Icon:
IFMT = ImageFormat.Icon;
break;
case ePictureFileFormat.Jpeg:
IFMT = ImageFormat.Jpeg;
break;
case ePictureFileFormat.Png:
IFMT = ImageFormat.Png;
break;
default:
IFMT = ImageFormat.Jpeg;
break;
}
image.Save(destfilename, IFMT);
image.Dispose();
bl = FileProcessor.FileExist(destfilename);
if (!bl)
{
return false;
}
Int32 filelen = FileProcessor.GetFileLength(destfilename);
return (filelen > 0);
}
/// <summary>
/// 變成黑白圖
/// </summary>
/// <param name="srcbitmap">原始圖</param>
/// <param name="mode">模式。0:加權平均 1:算數平均</param>
/// <returns></returns>
public static Bitmap ToGray(Bitmap bitmap, eGrayMode mode = eGrayMode.ArithmeticAverage)
{
if (bitmap == null)
{
return null;
}
int width = bitmap.Width;
int height = bitmap.Height;
byte newColor = 0;
try
{
BitmapData srcData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* curpix = (byte*)srcData.Scan0.ToPointer();
if (mode == eGrayMode.ArithmeticAverage)// 算數平均
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
newColor = (byte)((float)(curpix[0] + curpix[1] + curpix[2]) / 3.0f);
curpix[0] = newColor;
curpix[1] = newColor;
curpix[2] = newColor;
curpix += 3;
}
curpix += srcData.Stride - width * 3;
}
}
else
{
// 加權平均
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
newColor = (byte)((float)curpix[0] * 0.114f + (float)curpix[1] * 0.587f + (float)curpix[2] * 0.299f);
curpix[0] = newColor;
curpix[1] = newColor;
curpix[2] = newColor;
curpix += 3;
}
curpix += srcData.Stride - width * 3;
}
}
bitmap.UnlockBits(srcData);
}
}
catch
{
bitmap = null;
}
return bitmap;
}
/// <summary>
/// 獲取一幅圖片對應的所有像素亮度數組
/// </summary>
/// <param name="bitmap">原始圖</param>
/// <param name="brightnessary">亮度值數組</param>
/// <param name="mode">模式。0:加權平均 1:算數平均</param>
/// <returns></returns>
public static Boolean GetImageBrightness(Bitmap bitmap, ref Byte[] brightnessary,
eGrayMode mode = eGrayMode.WeightedAverage)
{
if (bitmap == null)
{
return false;
}
int width = bitmap.Width;
int height = bitmap.Height;
if (width < 1 || height < 1)
{
return false;
}
brightnessary = new Byte[width * height];
Boolean bl = false;
Int32 rowredundancy = 0;//每一行像素,對應的數組長度 與 實際像素點數的差值
Int32 pixidx = 0;//像素下標
try
{
BitmapData srcData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
rowredundancy = srcData.Stride - width * 3;//每行末尾還有這么多的冗余字節
unsafe
{
byte* curpix = (byte*)srcData.Scan0.ToPointer();
if (mode == eGrayMode.ArithmeticAverage)// 算數平均
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
brightnessary[pixidx] = (byte)((float)(curpix[0] + curpix[1] + curpix[2]) / 3.0f);
++pixidx;
curpix += 3;
}
curpix += rowredundancy;
}
}
else
{
// 加權平均
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
brightnessary[pixidx] = (byte)((float)curpix[0] * 0.114f + (float)curpix[1] * 0.587f + (float)curpix[2] * 0.299f);
++pixidx;
curpix += 3;
}
curpix += rowredundancy;
}
}
bitmap.UnlockBits(srcData);
}
bl = true;
}
catch(Exception ex)
{
bl = false;
Console.WriteLine("Get brightness ary error:" + ex.Message);
}
return bl;
}
/// <summary>
/// 變成黑白圖,每個元素都是一個像素的亮度
/// </summary>
/// <param name=" bitmap ">原始圖</param>
/// <param name=" graybitmap ">黑白圖</param>
/// <param name=" brightnessbytes ">黑白所有像素點亮度</param>
/// <param name="mode">模式。0:加權平均 1:算數平均</param>
/// <returns></returns>
public static Boolean ToGray(Bitmap bitmap, ref Bitmap graybitmap, ref Byte[] brightnessbytes,
eGrayMode mode = eGrayMode.WeightedAverage)
{
if (bitmap == null)
{
return false;
}
brightnessbytes = new Byte[bitmap.Width * bitmap.Height];
int width = bitmap.Width;
int height = bitmap.Height;
//Clone 可能引發 GDI+異常
graybitmap = new Bitmap(bitmap);
byte newColor = 0;
Int32 bytesidx = 0;
Boolean bl = false;
try
{
BitmapData srcData = graybitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* curpix = (byte*)srcData.Scan0.ToPointer();
if (mode == eGrayMode.ArithmeticAverage)// 算數平均
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
newColor = (byte)((float)(curpix[0] + curpix[1] + curpix[2]) / 3.0f);
brightnessbytes[bytesidx] = newColor;
++bytesidx;
curpix[0] = newColor;
curpix[1] = newColor;
curpix[2] = newColor;
curpix += 3;
}
curpix += srcData.Stride - width * 3;
}
}
else
{
// 加權平均
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
newColor = (byte)((float)curpix[0] * 0.114f + (float)curpix[1] * 0.587f + (float)curpix[2] * 0.299f);
brightnessbytes[bytesidx] = newColor;
++bytesidx;
curpix[0] = newColor;
curpix[1] = newColor;
curpix[2] = newColor;
curpix += 3;
}
curpix += srcData.Stride - width * 3;
}
}
graybitmap.UnlockBits(srcData);
}
bl = true;
}
catch(Exception ex)
{
graybitmap = null;
Console.WriteLine("ToGray error:" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 把圖片轉換為非黑即白的二色圖.
/// </summary>
/// <param name="bitmap">原始圖</param>
/// <param name="brightnessGate">亮度門限.超過此亮度認為白點,否則認為黑點</param>
/// <param name="bitary">每個像素點是否為黑點的數組</param>
/// <param name="trueAsblack">true-每個元素黑點為true,白點為false; false-每個元素白點為true,黑點為false</param>
/// <returns></returns>
public static Boolean ToBooleanArray(Bitmap bitmap, Byte brightnessGate, ref Boolean[] bitary, Boolean trueAsblack = true)
{
if (bitmap == null)
{
return false;
}
bitary = new Boolean[bitmap.Width * bitmap.Height];
int width = bitmap.Width;
int height = bitmap.Height;
byte curcolor = 0;
Int32 pixidx = 0;
Boolean bl = false;
try
{
BitmapData srcData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* curpix = (byte*)srcData.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
curcolor = (byte)((float)(curpix[0] + curpix[1] + curpix[2]) / 3.0f);
if (trueAsblack)//true為黑點
{
bitary[pixidx] = (curcolor < brightnessGate);
}
else
{
//true為白點
bitary[pixidx] = (curcolor > brightnessGate);
}
++pixidx;
curpix += 3;
}
curpix += srcData.Stride - width * 3;
}
bitmap.UnlockBits(srcData);
}
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("ToGray error:" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 亮度差數組變成bool數組.true表示亮度不同,false表示亮度相同
/// </summary>
/// <param name="bridiffary">亮度差數組</param>
/// <param name="brightnessGate">亮度門限.超過此亮度認為白點,否則認為黑點</param>
/// <returns></returns>
public static Boolean BrightnessToBoolean(Byte[] bridiffary, Byte brightnessGate, ref Boolean[] boolary)
{
if (bridiffary == null || bridiffary.Length < 4)
{
return false;
}
boolary = new Boolean[bridiffary.Length];
for (Int32 idx = 0; idx < bridiffary.Length; ++idx)
{
boolary[idx] = (bridiffary[idx] > brightnessGate);
}
return true;
}
#endregion
#region 圖片調整
/// <summary>
/// 調整亮度
/// </summary>
/// <param name="bitmap">原始圖</param>
/// <param name="degree">亮度,取值范圍-255 - 255</param>
/// <returns></returns>
public static Bitmap SetBrightness(Bitmap srcbitmap, int brightnessOffset)
{
if (srcbitmap == null)
{
return null;
}
CommonCompute.SetInt32Range(ref brightnessOffset, Const_MinBrightness, Const_MaxBrightness);
int width = srcbitmap.Width;
int height = srcbitmap.Height;
Bitmap bitmap = (Bitmap)srcbitmap.Clone();
try
{
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* curpix = (byte*)data.Scan0.ToPointer();
Int32 curcolor = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
curcolor = curpix[0] + brightnessOffset;
CommonCompute.SetInt32Range(ref curcolor, 0, Const_MaxBrightness);
curpix[0] = (byte)curcolor;
curcolor = curpix[1] + brightnessOffset;
CommonCompute.SetInt32Range(ref curcolor, 0, Const_MaxBrightness);
curpix[1] = (byte)curcolor;
curcolor = curpix[2] + brightnessOffset;
CommonCompute.SetInt32Range(ref curcolor, 0, Const_MaxBrightness);
curpix[2] = (byte)curcolor;
curpix += 3;
}
curpix += data.Stride - width * 3;
}
}
bitmap.UnlockBits(data);
}
catch
{
bitmap = null;
}
return bitmap;
}
/// <summary>
/// 調整圖像對比度
/// </summary>
/// <param name="bitmap">原始圖</param>
/// <param name="degree">對比度 0 - 100</param>
/// <returns></returns>
public static Bitmap SetContrast(Bitmap srcbitmap, int contrast)
{
if (srcbitmap == null)
{
return null;
}
//對比度取值范圍,0-100
CommonCompute.SetInt32Range(ref contrast, 0, 100);
Int32 curcolor = 0;
Bitmap bitmap = (Bitmap)srcbitmap.Clone();
int width = bitmap.Width;
int height = bitmap.Height;
//調整對比度基本思路:0時,所有像素點的亮度都設置為中間值128
//100 時,把亮度大於128的像素,亮度設置為255;小於128的設置為0
//即:50時,保持不變;小於50,所有點的亮度向中間值128偏移;大於50,所有點亮度值向兩端偏移
//如果當前像素點的亮度是130, 對比度為50時,結果仍然要是130,此時rate為1.0
//對比度為100時,結果要變成255,此時rate >= 128
//對比度為0時,結果要變成128,此時rate = 0
//因此可知對比度與rate的對應關系
//對比度: 0 50 100
//rate : 0 1 127
double rate = 0;
if (contrast == 50)
{
rate = 1;
}
else if (contrast < 50)
{
rate = contrast / 50.0;//小於50的,對比度比率必須是純小數,0-1 之間
}
else
{
rate = 1 + Const_MiddleBrightness * ((contrast - 50.0) / 50.0);//大於50的,比率必須是1到128之間的值
}
try
{
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* curpix = (byte*)data.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int i = 0; i < 3; i++) //R,G,B 3個通道
{
//對於 剛好亮度等於中間值的點,需要把亮度調高或調低1
//否則將無法實現對該點 提高對比度
if (curpix[i] == Const_MiddleBrightness)
{
curpix[i] = (byte)(curpix[i] + 1);
}
//調整該像素對比度
curcolor = (Int32)(Const_MiddleBrightness + (curpix[i] - Const_MiddleBrightness) * rate);
CommonCompute.SetInt32Range(ref curcolor, Const_MinBrightness, Const_MaxBrightness);
curpix[i] = (byte)curcolor;
++curpix;
}
}
curpix += data.Stride - width * 3;
}
}
bitmap.UnlockBits(data);
}
catch
{
bitmap = null;
}
return bitmap;
}
/// <summary>
/// 任意角度旋轉
/// </summary>
/// <param name="srcbitmap">原始圖Bitmap</param>
/// <param name="angle">旋轉角度</param>
/// <param name="bkColor">背景色</param>
/// <returns>輸出Bitmap</returns>
public static Bitmap Rotate(Bitmap srcbitmap, float angle, Color bkColor)
{
int w = srcbitmap.Width + 2;
int h = srcbitmap.Height + 2;
PixelFormat pf;
if (bkColor == Color.Transparent)
{
pf = PixelFormat.Format32bppArgb;
}
else
{
pf = srcbitmap.PixelFormat;
}
Bitmap tmp = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tmp);
g.Clear(bkColor);
g.DrawImageUnscaled(srcbitmap, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);
g = Graphics.FromImage(dst);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tmp, 0, 0);
g.Dispose();
tmp.Dispose();
return dst;
}
/// <summary>
/// Gamma校正
/// </summary>
/// <param name="srcbitmap">輸入Bitmap</param>
/// <param name="val">[0 <-明- 1 -暗-> 2]</param>
/// <returns>輸出Bitmap</returns>
public static Bitmap SetGamma(Bitmap srcbitmap, float val)
{
if (srcbitmap == null)
{
return null;
}
// 1表示無變化,就不做
if (val == 1.0000f) return srcbitmap;
try
{
Bitmap b = new Bitmap(srcbitmap.Width, srcbitmap.Height);
Graphics g = Graphics.FromImage(b);
ImageAttributes attr = new ImageAttributes();
attr.SetGamma(val, ColorAdjustType.Bitmap);
g.DrawImage(srcbitmap, new Rectangle(0, 0, srcbitmap.Width, srcbitmap.Height), 0, 0, srcbitmap.Width, srcbitmap.Height, GraphicsUnit.Pixel, attr);
g.Dispose();
return b;
}
catch
{
return null;
}
}
/// <summary>
/// 重新設置圖片尺寸
/// </summary>
/// <param name="srcbitmap">original Bitmap</param>
/// <param name="newW">new width</param>
/// <param name="newH">new height</param>
/// <returns>worked bitmap</returns>
public static Boolean ResizeImage(Bitmap srcimg, int newW, int newH, ref Bitmap destimage)
{
if (srcimg == null)
{
return false;
}
destimage = new Bitmap(newW, newH);
Graphics graph = Graphics.FromImage(destimage);
Boolean bl = true;
try
{
graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
graph.DrawImage(srcimg, new Rectangle(0, 0, newW, newH),
new Rectangle(0, 0, srcimg.Width, srcimg.Height),
GraphicsUnit.Pixel);
graph.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("ResizeImage error" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 去除噪點
/// </summary>
/// <param name="noisypointsize">噪點的尺寸</param>
/// <param name="bitmap">待處理的圖片信息</param>
/// <returns></returns>
public static Boolean RemoveNoisypoint(Int32 noisypointsize, ref Bitmap bitmap)
{
if (bitmap == null || noisypointsize < 1 ||
noisypointsize * 2 >= bitmap.Width || noisypointsize * 2 >= bitmap.Height)
{
return false;
}
// 創建過濾器
BlobsFiltering blobfilter =
new BlobsFiltering();
// 設置過濾條件(對象長、寬至少為70)
blobfilter.CoupledSizeFiltering = true;
blobfilter.MinWidth = noisypointsize;
blobfilter.MinHeight = noisypointsize;
blobfilter.ApplyInPlace(bitmap);
return true;
}
/// <summary>
/// 把圖片里指定區域的內容復制到另一個圖片里
/// </summary>
/// <param name="srcimg"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="destimg"></param>
/// <returns></returns>
public static Boolean CutImage(Bitmap srcimg, Int32 x, Int32 y, Int32 width, Int32 height, ref Bitmap destimg)
{
if (srcimg == null || x < 0 || y < 0 || width < 1 || height < 1 ||
x + width > srcimg.Width || y + height > srcimg.Height)
{
return false;
}
destimg = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics graph = Graphics.FromImage(destimg);
graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
graph.DrawImage(srcimg, new Rectangle(0, 0, width, height),
new Rectangle(x, y, width, height), GraphicsUnit.Pixel);
graph.Dispose();
return true;
}
#endregion
#region 亮度處理
/// <summary>
/// 獲取指定坐標處的亮度值
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetPixBrightness(Bitmap bitmap, Int32 x, Int32 y, eGrayMode mode, ref Byte brightness)
{
if (bitmap == null)
{
return false;
}
if (x < 0 || x >= bitmap.Width ||
y < 0 || y >= bitmap.Height)
{
return false;
}
Color curColor = bitmap.GetPixel(x, y);
//利用公式計算灰度值(加權平均法)
if (mode == eGrayMode.ArithmeticAverage)
{
brightness = (Byte)(curColor.R * 0.299f + curColor.G * 0.587f + curColor.B * 0.114f);
}
else
{
brightness = (Byte)((curColor.R + curColor.G + curColor.B) / 3.0f);
}
return true;
}
/// <summary>
/// 獲取指定坐標處的亮度值
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetPixBrightness(Byte[] bribytes, Int32 width,Int32 height,
Int32 x, Int32 y, ref Byte brightness)
{
if (bribytes == null || width < 1 || height < 1 ||
x < 0 || x >= width ||
y < 0 || y >= height ||
bribytes.Length != width * height)
{
return false;
}
brightness = bribytes[y * width + x];
return true;
}
/// <summary>
/// 獲取指定坐標處的亮度值
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetPixBrightnessByRate(Byte[] bribytes, Int32 width, Int32 height,
double xRate, double yRate, ref Byte brightness)
{
int x = (int)(width * xRate);
int y = (int)(height * yRate);
if (bribytes == null || width < 1 || height < 1 ||
x < 0 || x >= width ||
y < 0 || y >= height ||
bribytes.Length != width * height)
{
return false;
}
brightness = bribytes[y * width + x];
return true;
}
/// <summary>
/// 獲取指定坐標處的顏色
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetPixColor(Bitmap bitmap, Int32 x, Int32 y, ref Color curColor)
{
if (bitmap == null)
{
return false;
}
if (x < 0 || x >= bitmap.Width ||
y < 0 || y >= bitmap.Height)
{
return false;
}
curColor = bitmap.GetPixel(x, y);
return true;
}
/// <summary>
/// 獲取指定坐標處的顏色
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetPixColorByRate(Bitmap bitmap, double xRate, double yRate, ref Color curColor)
{
if (bitmap == null)
{
return false;
}
int width = bitmap.Width;
int height = bitmap.Height;
int X = (int)(width * xRate);
int Y = (int)(height * yRate);
Boolean bl = GetPixColor(bitmap, X, Y, ref curColor);
return bl;
}
/// <summary>
/// 把顏色轉換為亮度值
/// </summary>
/// <param name="bitmap"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Boolean GetBrightnessByColor(Color curColor, eGrayMode mode, ref Byte brightness)
{
if (curColor == null)
{
return false;
}
//利用公式計算灰度值(加權平均法)
if (mode == eGrayMode.ArithmeticAverage)
{
brightness = (Byte)(curColor.R * 0.299f + curColor.G * 0.587f + curColor.B * 0.114f);
}
else
{
brightness = (Byte)((curColor.R + curColor.G + curColor.B) / 3.0f);
}
return true;
}
#endregion
#region 圖片比較
/// <summary>
/// 根據2個圖片的亮度值,比較圖片的差異部分
/// </summary>
/// <param name="brightnessDiff"></param>
/// <param name="compareret"></param>
/// <returns></returns>
public static Boolean CompareImageBrightness(Byte brightnessDiff,
Byte[] brightness1, Byte[] brightness2,
ref Boolean[] diffPixArray)
{
if (brightness1 == null || brightness2 == null ||
brightness1.Length < 1 || brightness2.Length < 1 ||
brightness1.Length != brightness2.Length)
{
return false;
}
Int32 arylen = brightness1.Length;
diffPixArray = new Boolean[brightness1.Length];
Byte bri1 = 0;
Byte bri2 = 0;
for (Int32 byteidx = 0; byteidx < arylen; ++byteidx)
{
bri1 = brightness1[byteidx];
bri2 = brightness2[byteidx];
//亮度差超過指定范圍
if (bri1 >= bri2 + brightnessDiff ||
bri2 >= bri1 + brightnessDiff)
{
diffPixArray[byteidx] = true;
}
}
return true;
}
/// <summary>
/// 把2個圖片的尺寸設置為一樣大
/// </summary>
/// <param name="image1"></param>
/// <param name="image2"></param>
/// <returns></returns>
public static Boolean ResizeImageToSame(ref Bitmap image1, ref Bitmap image2)
{
if (image1 == null || image2 == null ||
image1.Width == 0 || image1.Height == 0 ||
image2.Width == 0 || image2.Height == 0)
{
return false;
}
//如果2個圖片尺寸不一樣,把大的尺寸壓縮小了再比較
Boolean bl = false;
Bitmap tmpimg = null;
if (image1.Width > image2.Width && image1.Height < image2.Height)
{
return false;
}
if (image1.Width < image2.Width && image1.Height > image2.Height)
{
return false;
}
//image1 比較大,把image2放大到 與1一樣大
if (image1.Width > image2.Width && image1.Height > image2.Height)
{
bl = ResizeImage(image2, image1.Width, image1.Height, ref tmpimg);
image2 = tmpimg;
}
//image 2比較大,把image1放大到 與2一樣大
if (image1.Width < image2.Width && image1.Height < image2.Height)
{
bl = ResizeImage(image1, image2.Width, image2.Height, ref tmpimg);
image1 = tmpimg;
}
return true;
}
/// <summary>
/// 根據2個圖片的像素顏色值,比較圖片的差異部分
/// </summary>
/// <param name="compareparam"></param>
/// <param name="compareret"></param>
/// <returns></returns>
public static Boolean CompareImage(ImageCompareParameter compareparam,
ref ImageCompareResult compareret)
{
Bitmap image1 = compareparam.Image1;
Bitmap image2 = compareparam.Image2;
Int32 briDiff = compareparam.BrightnessDiff;
Color diffColor = compareparam.DifferentAreaFillColor;
Color samecolor = compareparam.SameAreaFillColor;
//是否需要填充相同或不同部分的像素的顏色
Boolean filldiffcolor = (diffColor != Color.Transparent);
Boolean fillsamecolor = (samecolor != Color.Transparent);
//如果圖片尺寸不一樣,修改為一樣大
Boolean bl = ResizeImageToSame(ref image1, ref image2);
if (!bl)
{
return false;
}
Bitmap imagediff = (Bitmap)image1.Clone();
//不同區域的左上下右位置
Int32 areaLeft = imagediff.Width;
Int32 areaTop = imagediff.Height;
Int32 areaRight = -1;
Int32 areaBottom = -1;
int width = image1.Width;
int height = image1.Height;
long allpixcnt = height * width;//所有像素點數量
long diffpixcnt = 0;//不同像素點數量
long samepixcnt = 0;//相同像素點數量
//3張圖片的各像素亮度數組
Int32 briaryidx = 0;
Byte[] briary1 = new Byte[allpixcnt];
Byte[] briary2 = new Byte[allpixcnt];
Byte[] briaryret = new Byte[allpixcnt];
Byte diffB = diffColor.B;
Byte diffG = diffColor.G;
Byte diffR = diffColor.R;
Byte sameB = samecolor.B;
Byte sameG = samecolor.G;
Byte sameR = samecolor.R;
Byte samebri = 0;
Byte diffbri = 0;
GetBrightnessByColor(diffColor, eGrayMode.WeightedAverage, ref samebri);
GetBrightnessByColor(diffColor, eGrayMode.WeightedAverage, ref diffbri);
try
{
BitmapData data1 = image1.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData data2 = image2.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData datadiff = imagediff.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte bri1 = 0;
byte bri2 = 0;
//每個像素是否相同.1相同,0不同
compareret.PixIsDifferent = new Boolean[width * height];
//當前像素是否不同
Boolean curpixIsdiff = false;
unsafe
{
byte* curpix1 = (byte*)data1.Scan0.ToPointer();
byte* curpix2 = (byte*)data2.Scan0.ToPointer();
byte* curpixdiff = (byte*)datadiff.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//利用公式計算灰度值(加權平均法)
//按BGR的順序存儲
bri1 = (Byte)(curpix1[0] * 0.114f + curpix1[1] * 0.587f + curpix1[2] * 0.299f);
bri2 = (Byte)(curpix2[0] * 0.114f + curpix2[1] * 0.587f + curpix2[2] * 0.299f);
//以1作為基准,比較1和2之間的差距,如果超過閥值,認為當前像素有差異
//否則認為當前像素沒有差異
curpixIsdiff = false;
if (bri1 >= bri2 + briDiff ||
bri2 >= bri1 + briDiff)
{
curpixIsdiff = true;
}
briary1[briaryidx] = bri1;
briary2[briaryidx] = bri2;
if (curpixIsdiff) //如果有差異,設置圖像1里的當前像素為 不同顏色
{
if (filldiffcolor)
{
curpixdiff[0] = diffB;
curpixdiff[1] = diffG;
curpixdiff[2] = diffR;
}
++diffpixcnt;
if (x < areaLeft) //記憶最左邊的像素位置
{
areaLeft = x;
}
if (x > areaRight) //記憶最右邊的像素位置
{
areaRight = x;
}
if (y < areaTop) //記憶最上邊的像素位置
{
areaTop = y;
}
if (y > areaBottom) //記憶最下邊的像素位置
{
areaBottom = y;
}
//記憶當前像素的比較結果的亮度
briaryret[briaryidx] = diffbri;
}
else //沒有差異,設置結果里的當前像素為 相同顏色
{
if (fillsamecolor)
{
curpixdiff[0] = sameB;
curpixdiff[1] = sameG;
curpixdiff[2] = sameR;
}
++samepixcnt;
//記憶當前像素的比較結果的亮度
briaryret[briaryidx] = samebri;
}
// 比較結果的亮度數組下標
++briaryidx;
//像素是否不同的標志
compareret.PixIsDifferent[y * width + x] = curpixIsdiff;
curpix1 += 3;
curpix2 += 3;
curpixdiff += 3;
}
curpix1 += data1.Stride - width * 3;
curpix2 += data1.Stride - width * 3;
curpixdiff += datadiff.Stride - width * 3;
}
}
image1.UnlockBits(data1);
image2.UnlockBits(data2);
imagediff.UnlockBits(datadiff);
compareret.RateDifferent = diffpixcnt / (double)allpixcnt;
compareret.RateSame = samepixcnt / (double)allpixcnt;
compareret.CompareResultImage = imagediff;
compareret.BrightnessDiff = briDiff;
compareret.BrightnessBytesImage1 = briary1;
compareret.BrightnessBytesImage2 = briary2;
compareret.BrightnessBytesResult = briaryret;
//保存區域范圍
//compareret.DiffAreaTop = areaTop;
//compareret.DiffAreaLeft = areaLeft;
//compareret.DiffAreaRight = areaRight;
//compareret.DiffAreaBottom = areaBottom;
//compareret.CalculateAreaRate();
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("CompareImage error:" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 2張圖片亮度值相減,得到新圖片以及亮度值
/// </summary>
/// <param name="image1"></param>
/// <param name="image2"></param>
/// <param name="retimage"></param>
/// <param name="brightnessary"></param>
/// <returns></returns>
public static Boolean SubtractImageBrightness(Bitmap image1, Bitmap image2,
ref Bitmap imagediff, ref Byte[] brightnessary)
{
if (image1 == null || image2 == null)
{
return false;
}
Boolean bl = ResizeImageToSame(ref image1, ref image2);
if (!bl)
{
return false;
}
int width = image1.Width;
int height = image1.Height;
long allpixcnt = height * width;//所有像素點數量
brightnessary = new Byte[allpixcnt];
imagediff = new Bitmap(image1);
Int32 pixidx = 0;//當前像素下標
byte bri1 = 0;
byte bri2 = 0;
BitmapData data1 = null;
BitmapData data2 = null;
BitmapData datadiff = null;
//每行末尾還有這么多的冗余字節
Int32 rowredundancy = 0;
try
{
data1 = image1.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
data2 = image2.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
datadiff = imagediff.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
rowredundancy = datadiff.Stride - width * 3;//每行末尾還有這么多的冗余字節
Byte bridiff = 0;
unsafe
{
byte* curpix1 = (byte*)data1.Scan0.ToPointer();
byte* curpix2 = (byte*)data2.Scan0.ToPointer();
byte* cmpretpix = (byte*)datadiff.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
bri1 = (byte)((float)(curpix1[0] + curpix1[1] + curpix1[2]) / 3.0f);
bri2 = (byte)((float)(curpix2[0] + curpix2[1] + curpix2[2]) / 3.0f);
bridiff = (bri1 > bri2) ? (Byte)(bri1 - bri2) : (Byte)(bri2 - bri1); //計算當前像素點的亮度值
brightnessary[pixidx] = bridiff;//保存亮度值
++pixidx;
cmpretpix[0] = bridiff;//把亮度值設置到結果圖像里
cmpretpix[1] = bridiff;
cmpretpix[2] = bridiff;
curpix1 += 3;
curpix2 += 3;
cmpretpix += 3;
}
curpix1 += rowredundancy;
curpix2 += rowredundancy;
cmpretpix += rowredundancy;
}
}
image1.UnlockBits(data1);
image2.UnlockBits(data2);
imagediff.UnlockBits(datadiff);
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("CompareImage error:" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 根據2個圖片的亮度值,比較圖片的差異部分,並對比較結果的圖片執行去噪點處理
/// </summary>
/// <param name="image1"></param>
/// <param name="image2"></param>
/// <param name="bridiff">亮度容差</param>
/// <param name="noisypointsize">噪點邊長</param>
/// <param name="imagediff">比較結果的圖片</param>
/// <param name="diffary">每個像素是否相同</param>
/// <returns></returns>
public static Boolean CompareImageByBrightness(Bitmap image1, Bitmap image2,
Int32 briDiff, Int32 noisypointsize,
ref Bitmap imagediff, ref Boolean[] diffary)
{
if (image1 == null || image2 == null)
{
return false;
}
Boolean bl = ResizeImageToSame(ref image1, ref image2);
if (!bl)
{
return false;
}
if (briDiff < 1 || briDiff > 255)
{
return false;
}
if (noisypointsize < 1 || noisypointsize * 2 > image1.Height)
{
return false;
}
int width = image1.Width;
int height = image1.Height;
long allpixcnt = height * width;//所有像素點數量
imagediff = new Bitmap(image1);
//每個像素是否相同.1相同,0不同
diffary = new Boolean[width * height];
Int32 pixidx = 0;//當前像素下標
byte bri1 = 0;
byte bri2 = 0;
BitmapData data1 = null;
BitmapData data2 = null;
BitmapData datadiff = null;
//每行末尾還有這么多的冗余字節
Int32 rowredundancy = 0;
try
{
data1 = image1.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
data2 = image2.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
datadiff = imagediff.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
rowredundancy = datadiff.Stride - width * 3;//每行末尾還有這么多的冗余字節
unsafe
{
byte* curpix1 = (byte*)data1.Scan0.ToPointer();
byte* curpix2 = (byte*)data2.Scan0.ToPointer();
byte* cmpretpix = (byte*)datadiff.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
bri1 = (byte)((float)(curpix1[0] + curpix1[1] + curpix1[2]) / 3.0f);
bri2 = (byte)((float)(curpix2[0] + curpix2[1] + curpix2[2]) / 3.0f);
//比較2個像素亮度值之差,如果有差異,設置圖像1里的當前像素為 不同顏色
if (bri1 >= bri2 + briDiff ||
bri2 >= bri1 + briDiff)
{
diffary[pixidx] = true;
cmpretpix[0] = Const_WhiteBrightness;
cmpretpix[1] = Const_WhiteBrightness;
cmpretpix[2] = Const_WhiteBrightness;
}
else
{
diffary[pixidx] = false;
cmpretpix[0] = Const_BlackBrightness;
cmpretpix[1] = Const_BlackBrightness;
cmpretpix[2] = Const_BlackBrightness;
}
++pixidx;
curpix1 += 3;
curpix2 += 3;
cmpretpix += 3;
}
curpix1 += rowredundancy;
curpix2 += rowredundancy;
cmpretpix += rowredundancy;
}
}
image1.UnlockBits(data1);
image2.UnlockBits(data2);
imagediff.UnlockBits(datadiff);
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("CompareImage error:" + ex.Message);
bl = false;
}
//現在對圖像執行去噪點處理
RemoveNoisypoint(noisypointsize, ref imagediff);
//獲取去除噪點后各像素亮度
Byte pixbri = 0;//當前像素亮度
pixidx = 0;
try
{
datadiff = imagediff.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* cmpretpix = (byte*)datadiff.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
pixbri = (byte)((float)(cmpretpix[0] + cmpretpix[1] + cmpretpix[2]) / 3.0f);
//去除噪點后,已經變得非黑即白.如果是黑色,表示相同,白色,表示不同
diffary[pixidx] = (pixbri > briDiff);
++pixidx;
cmpretpix += 3;
}
cmpretpix += rowredundancy;
}
}
imagediff.UnlockBits(datadiff);
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("CompareImage error:" + ex.Message);
bl = false;
}
return bl;
}
/// 根據2個圖片的亮度值,比較圖片的差異部分
/// </summary>
/// <param name="compareparam"></param>
/// <param name="compareret"></param>
/// <returns></returns>
public static Boolean CompareImageByBrightness(ImageCompareParameter compareparam,
ref ImageCompareResult compareret)
{
Bitmap image1 = compareparam.Image1;
Bitmap image2 = compareparam.Image2;
Byte[] imagebri1 = compareparam.BrightnessBytesImage1;
Byte[] imagebri2 = compareparam.BrightnessBytesImage2;
Int32 briDiff = compareparam.BrightnessDiff;
Color diffColor = compareparam.DifferentAreaFillColor;
Color samecolor = compareparam.SameAreaFillColor;
//是否需要填充相同或不同部分的像素的顏色
Boolean filldiffcolor = (diffColor != Color.Transparent);
Boolean fillsamecolor = (samecolor != Color.Transparent);
Boolean bl = false;
Bitmap imagediff = new Bitmap(image1);
//不同區域的左上下右位置
Int32 areaLeft = imagediff.Width;
Int32 areaTop = imagediff.Height;
Int32 areaRight = -1;
Int32 areaBottom = -1;
int width = image1.Width;
int height = image1.Height;
long allpixcnt = height * width;//所有像素點數量
long diffpixcnt = 0;//不同像素點數量
long samepixcnt = 0;//相同像素點數量
if (imagebri1 == null || imagebri2 == null ||
imagebri2.Length != imagebri2.Length ||
imagebri2.Length != allpixcnt)
{
return false;
}
//3張圖片的各像素亮度數組
Int32 briaryidx = 0;
Byte[] briaryret = new Byte[allpixcnt];
Byte diffB = diffColor.B;
Byte diffG = diffColor.G;
Byte diffR = diffColor.R;
Byte sameB = samecolor.B;
Byte sameG = samecolor.G;
Byte sameR = samecolor.R;
Byte samebri = 0;
Byte diffbri = 0;
GetBrightnessByColor(diffColor, eGrayMode.WeightedAverage, ref samebri);
GetBrightnessByColor(diffColor, eGrayMode.WeightedAverage, ref diffbri);
Int32 currowfirstx = 0;//當前行的首個像素的下標
try
{
BitmapData data1 = image1.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData data2 = image2.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData datadiff = imagediff.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte bri1 = 0;
byte bri2 = 0;
//每個像素是否相同.1相同,0不同
compareret.PixIsDifferent = new Boolean[width * height];
//當前像素是否不同
Boolean curpixIsdiff = false;
unsafe
{
byte* curpix1 = (byte*)data1.Scan0.ToPointer();
byte* curpix2 = (byte*)data2.Scan0.ToPointer();
byte* cmpretpix = (byte*)datadiff.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
currowfirstx = y * width;
for (int x = 0; x < width; x++)
{
bri1 = imagebri1[currowfirstx + x];
bri2 = imagebri2[currowfirstx + x];
//以1作為基准,比較1和2之間的差距,如果超過閥值,認為當前像素有差異
//否則認為當前像素沒有差異
curpixIsdiff = false;
if (bri1 >= bri2 + briDiff ||
bri2 >= bri1 + briDiff)
{
curpixIsdiff = true;
}
if (curpixIsdiff) //如果有差異,設置圖像1里的當前像素為 不同顏色
{
if (filldiffcolor)
{
cmpretpix[0] = diffB;
cmpretpix[1] = diffG;
cmpretpix[2] = diffR;
}
++diffpixcnt;
if (x < areaLeft) //記憶最左邊的像素位置
{
areaLeft = x;
}
if (x > areaRight) //記憶最右邊的像素位置
{
areaRight = x;
}
if (y < areaTop) //記憶最上邊的像素位置
{
areaTop = y;
}
if (y > areaBottom) //記憶最下邊的像素位置
{
areaBottom = y;
}
//記憶當前像素的比較結果的亮度
briaryret[briaryidx] = diffbri;
}
else //沒有差異,設置結果里的當前像素為 相同顏色
{
if (fillsamecolor)
{
cmpretpix[0] = sameB;
cmpretpix[1] = sameG;
cmpretpix[2] = sameR;
}
++samepixcnt;
//記憶當前像素的比較結果的亮度
briaryret[briaryidx] = samebri;
}
// 比較結果的亮度數組下標
++briaryidx;
//像素是否不同的標志
compareret.PixIsDifferent[currowfirstx + x] = curpixIsdiff;
curpix1 += 3;
curpix2 += 3;
cmpretpix += 3;
}
curpix1 += data1.Stride - width * 3;
curpix2 += data1.Stride - width * 3;
cmpretpix += datadiff.Stride - width * 3;
}
}
image1.UnlockBits(data1);
image2.UnlockBits(data2);
imagediff.UnlockBits(datadiff);
compareret.RateDifferent = diffpixcnt / (double)allpixcnt;
compareret.RateSame = samepixcnt / (double)allpixcnt;
compareret.CompareResultImage = imagediff;
compareret.BrightnessDiff = briDiff;
compareret.BrightnessBytesResult = briaryret;
bl = true;
}
catch (Exception ex)
{
Console.WriteLine("CompareImage error:" + ex.Message);
bl = false;
}
return bl;
}
/// <summary>
/// 獲取一個區域的實際坐標
/// </summary>
/// <param name="area"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="x1"></param>
/// <param name="y1"></param>
/// <param name="x2"></param>
/// <param name="y2"></param>
public static void GetAreaPositionInImage(ImageAreaInfo area,
Int32 width, Int32 height,
ref Int32 x1, ref Int32 y1, ref Int32 x2, ref Int32 y2)
{
if (area.PositionType == ePositionType.ByPix)
{
x1 = (Int32)area.X1;
y1 = (Int32)area.Y1;
x2 = (Int32)area.X2;
y2 = (Int32)area.Y2;
}
else
{
x1 = (Int32)(area.X1 * (double)width);
y1 = (Int32)(area.Y1 * (double)height);
x2 = (Int32)(area.X2 * (double)width);
y2 = (Int32)(area.Y2 * (double)height);
}
}
/// <summary>
/// 檢查指定區域的圖像是否與方案里的指定值一樣(都是相同或者不同)
/// </summary>
/// <param name="briDiffary">每個元素對應2張圖片的每個像素亮度相同還是不同.true不同,false相同</param>
/// <param name="area"></param>
/// <returns></returns>
public static Boolean ValidateImageArea(Boolean[] briDiffary, ImageAreaInfo area, Int32 width, Int32 height)
{
if (briDiffary == null || briDiffary.Length < 4 || area == null ||
width < 1 || height < 1 || width * height != briDiffary.Length)
{
return false;
}
Int32 x1 = 0;
Int32 x2 = 0;
Int32 y1 = 0;
Int32 y2 = 0;
//獲取該區域在圖像里的實際坐標范圍
GetAreaPositionInImage(area, width, height,
ref x1, ref y1, ref x2, ref y2);
//獲取該區域里的像素匹配類型
eAreaDifferentType difftype = eAreaDifferentType.Partial;
Boolean bl = GetImageAreaDifferentType(briDiffary, width, height,
x1, y1, x2, y2, ref difftype);
if (!bl)
{
return false;
}
//如果是期待所有像素都是相同,要求必須每個像素都相同.任何一個不同,就認為失敗
if (area.ExpectDispMode == eDrawType.ExpectHide &&
difftype != eAreaDifferentType.AllSame)
{
return false;
}
//如果是期待像素不同,只要有1個像素不同就可以.所有像素都相同,認為失敗
if (area.ExpectDispMode == eDrawType.ExpectShow &&
difftype == eAreaDifferentType.AllSame)
{
return false;
}
return true;
}
/// <summary>
/// 檢查指定區域的圖像是否與方案里的指定值一樣(都是相同或者不同)
/// </summary>
/// <param name="pixDiffary"></param>
/// <param name="area"></param>
/// <returns></returns>
public static Boolean ValidateImageArea(Byte[] briDiffary, ImageAreaInfo area, Int32 width, Int32 height)
{
Boolean[] blary = new Boolean[briDiffary.Length];
for (Int32 idx = 0; idx < briDiffary.Length; ++idx)
{
blary[idx] = (briDiffary[idx] > 0);
}
Boolean bl = ValidateImageArea(blary, area, width, height);
return bl;
}
/// <summary>
/// 檢查圖片的比較結果里,某個區域是否與期待的一致
/// </summary>
/// <param name="compareret"></param>
/// <param name="area"></param>
/// <returns>true-與期待一致;false-不一致</returns>
public static Boolean ValidateImageArea(ImageCompareResult compareret, ImageAreaInfo area)
{
Boolean[] pixDiffary = compareret.PixIsDifferent;
Bitmap tmp = new Bitmap(compareret.CompareResultImage);
Int32 width = tmp.Width;
Int32 height = tmp.Height;
Boolean bl = ValidateImageArea(compareret.PixIsDifferent, area, width, height);
return bl;
}
/// <summary>
/// 獲取1個 比較結果里,指定的區域范圍,是全都相同,還是不同
/// 只有所有像素都是相同,才認為是整個區域相同
/// 如果有1個像素不同,則認為整個區域不同
/// </summary>
/// <param name="pixDiffary"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="startX"></param>
/// <param name="startY"></param>
/// <param name="endX"></param>
/// <param name="endY"></param>
/// <returns> </returns>
public static Boolean GetImageAreaDifferentType(Boolean[] pixDiffary, Int32 width, Int32 height,
Int32 x1, Int32 y1, Int32 x2, Int32 y2, ref eAreaDifferentType difftype)
{
Int32 areawidth = x2 - x1;
Int32 areaheight = y2 - y1;
if (pixDiffary == null || width < 1 || height < 1 ||
areawidth < 1 || areaheight < 1 ||
width < areawidth || height < areaheight ||
pixDiffary.Length < width * height)
{
return false;
}
Boolean allissame = false; //假設所有像素相同
Boolean allisdiff = false; //假設所有像素不同
Int32 currowFirstPix = 0;
for (Int32 y = y1; y <= y2; ++y)
{
currowFirstPix = y * width;
for (Int32 x = x1; x <= x2; ++x)
{
if (pixDiffary[currowFirstPix + x]) //當前像素點不同
{
allisdiff = true;
}
else//當前像素相同
{
allissame = true;
}
//如果已經有部分相同部分不同,退出
if (allisdiff && allissame)
{
difftype = eAreaDifferentType.Partial;
return true;
}
}
}
//現在,所有像素都相同,或都不同
if (allisdiff)
{
difftype = eAreaDifferentType.AllDifferent;
}
else
{
difftype = eAreaDifferentType.AllSame;
}
return true;
}
/// <summary>
/// 根據亮度容差,把圖片轉換為非黑即白的圖片
/// </summary>
/// <param name="briimg"></param>
/// <param name="brigate"></param>
/// <returns></returns>
public static Boolean GetBlackWhiteImage(Bitmap briimg, Byte[] briDiffary, Int32 brigate, ref Bitmap blackwhiteimage)
{
if (briimg == null)
{
return false;
}
int width = briimg.Width;
int height = briimg.Height;
long allpixcnt = height * width;//所有像素點數量
if (briDiffary == null || briDiffary.Length != allpixcnt)
{
return false;
}
blackwhiteimage = new Bitmap(briimg);
Int32 pixidx = 0;//當前像素下標
BitmapData datasrc = null;
BitmapData dataret = null;
//每行末尾還有這么多的冗余字節
Int32 rowredundancy = 0;
Byte curpixBri = 0;//當前的亮度
try
{
datasrc = briimg.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
dataret = blackwhiteimage.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
rowredundancy = datasrc.Stride - width * 3;//每行末尾還有這么多的冗余字節
unsafe
{
byte* pixret = (byte*)dataret.Scan0.ToPointer();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//亮度差值大於門限的,認為是不同部分,用白色填充
curpixBri = (briDiffary[pixidx] > brigate) ? Const_BrightnessWhite : Const_BrightnessBlack;
pixret[0] = curpixBri;//把亮度值設置到結果圖像里
pixret[1] = curpixBri;
pixret[2] = curpixBri;
++pixidx;
pixret += 3;
}
pixret += rowredundancy;
}
}
briimg.UnlockBits(datasrc);
blackwhiteimage.UnlockBits(dataret);
}
catch (Exception ex)
{
Console.WriteLine("GetBlackWhiteImage error:" + ex.Message);
return false;
}
return true;
}
#endregion
#region 內部實現
/// <summary>
/// 比較2個數值之間的差是否大於指定值
/// </summary>
/// <param name="val1"></param>
/// <param name="val2"></param>
/// <param name="diff"></param>
/// <returns>超過指定值返回true;否則返回false</returns>
private static Boolean CheckDiffOver(Int32 val1, Int32 val2, Int32 diff)
{
if (diff < 1)
{
return false;
}
if (val1 > val2 && val1 > val2 + diff)
{
return true;
}
if (val2 > val1 && val2 > val1 + diff)
{
return true;
}
return false;
}
#endregion
}
}