C#使用ESC指令控制POS打印機打印小票


 

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

    }

}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM