吴昊品工程级别软件项目 Round 3 —— 一个简易的字符识别系统(OCR技术+VB实现)


如图,是一个简易的OCR系统。我在大二下学期的时候参加过华科的信息安全竞 赛,准备做一个简易的舆情监控系统。当然,最终还是没有实现的,但是,在这个过程中尝试过一些东西,比如图像识别技术(OCR)就是一种尝试。这款软件是 一位高中的学生做出的,他的名字叫——陨落雕(ThirdApple),识别率说还可以,当然,这个还是很不行的。而且,不存在机器学习的功能,只能识别 一些给定的文本(0--9以及所有的英文字母),这是这款软件的缺陷。

  关于Visual Basic 6.0SP6(很多人之所以不使用最新的VS2010系列而使用老式的6.0,也是因为它的经典性以及便携性,比如我的迅雷5.0,一直都不愿意升级为7.0,哪怕是界面确实漂亮一些),很老式的一款软件,这里就不介绍了。

  工程目录:

  吴昊品工程级别软件项目 Round 3 —— 一个简易的字符识别系统(OCR技术+VB实现)

  分为窗体,模块和用户控件三个部分。

  VB是解释型的语言,分一个个Sub对事件进行处理。

  Private Sub CmdClear_Click() '清理手写输入框(清除按钮)
PicPrint.Cls
SapText.Visible = False
End Sub

Private Sub CmdFont_Click() '选择文字大小和字体(字体按钮)
On Error GoTo Error
  With CDFont
    .Flags = cdlCFBoth
    .FontName = PicSample.FontName //字体名
    .FontSize = PicSample.FontSize //字体大小
    .FontBold = PicSample.FontBold //字形
    .FontItalic = PicSample.FontItalic //字符集
    .ShowFont
  End With
  With PicSample
    .FontName = CDFont.FontName
    .FontSize = CDFont.FontSize
    .FontBold = CDFont.FontBold
    .FontItalic = CDFont.FontItalic
  End With
  With TxtSample //由于是软件使用者自己输入的,所以不需要字符集
    .FontName = CDFont.FontName
    '.FontSize = CDFont.FontSize
    .FontBold = CDFont.FontBold
  End With
Error:
End Sub

Private Sub CmdRead_Click() '进行识别
Dim CutPic As RECT //定义一个RECT类型的数据
ListSame.Clear '清空List框
CutPic = CutLetters(PicPrint) '将PicPrint中的手写文本剪切
SapText.Left = CutPic.Left
SapText.Width = CutPic.Right - CutPic.Left
SapText.Top = CutPic.Top
SapText.Height = CutPic.Bottom - CutPic.Top
SapText.Visible = True
ReDim OcrText(1 To Len(TxtSample.Text)) '重新定义OcrText数组的长度
For i = 1 To Len(TxtSample.Text) '循环进行匹配度校验(对每一个计算匹配度)
  OcrText(i).ModeText = Mid(TxtSample.Text, i, 1) '取得文字
  PicSample.Width = PicSample.TextWidth(OcrText(i).ModeText) '初步设置大小
  PicSample.Height = PicSample.TextHeight(OcrText(i).ModeText)
  PicSample.CurrentX = 0
  PicSample.CurrentY = 0
  PicSample.Cls
  PicSample.Print OcrText(i).ModeText '输出标准文本
  CutPic = CutLetters(PicSample) '剪切标准文本
  BitBlt PicSample.hdc, 0, 0, CutPic.Right - CutPic.Left, CutPic.Bottom - CutPic.Top, PicSample.hdc, CutPic.Left, CutPic.Top, vbSrcCopy
  PicSample.Refresh
  PicSample.Width = CutPic.Right - CutPic.Left
  PicSample.Height = CutPic.Bottom - CutPic.Top
  PicSample.Left = (PicSampleOutSide.ScaleWidth - PicSample.ScaleWidth) / 2
  PicSample.Top = (PicSampleOutSide.ScaleHeight - PicSample.ScaleHeight) / 2
  PicPrintMode.Width = PicSample.Width
  PicPrintMode.Height = PicSample.Height
  StretchBlt PicPrintMode.hdc, 0, 0, PicPrintMode.ScaleWidth, PicPrintMode.ScaleHeight, PicPrint.hdc, SapText.Left, SapText.Top, SapText.Width, SapText.Height, vbSrcCopy
  BlackBits PicSample '对标准文本二值化(二值化处理是图像处理的一个重要过程)
  OcrText(i).SameBits = OcrBits(PicPrintMode, PicSample) '进行匹配度校验
  DoEvents
Next i
Kspxd OcrText, 1, Len(TxtSample.Text) '对匹配进行排序
For i = Len(TxtSample.Text) To 1 Step -1 '输出到List框中
  ListSame.AddItem OcrText(i).ModeText & "的相似度:" & CStr(Round(OcrText(i).SameBits / 100, 2)) & "%"
Next i
'显示最匹配文字到标准文本输出框
TxtPrint.Text = TxtPrint.Text & OcrText(Len(TxtSample.Text)).ModeText
PicSample.Width = PicSample.TextWidth(OcrText(Len(TxtSample.Text)).ModeText)
PicSample.Height = PicSample.TextHeight(OcrText(Len(TxtSample.Text)).ModeText)
PicSample.CurrentX = 0
PicSample.CurrentY = 0
PicSample.Cls
PicSample.Print OcrText(Len(TxtSample.Text)).ModeText
CutPic = CutLetters(PicSample)
BitBlt PicSample.hdc, 0, 0, CutPic.Right - CutPic.Left, CutPic.Bottom - CutPic.Top, PicSample.hdc, CutPic.Left, CutPic.Top, vbSrcCopy
PicSample.Refresh
PicSample.Width = CutPic.Right - CutPic.Left
PicSample.Height = CutPic.Bottom - CutPic.Top
PicSample.Left = (PicSampleOutSide.ScaleWidth - PicSample.ScaleWidth) / 2
PicSample.Top = (PicSampleOutSide.ScaleHeight - PicSample.ScaleHeight) / 2
End Sub

Private Sub Form_Load()
PicPrint.DrawWidth = 10 '设置笔刷大小
TxtSample.Text = "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" '设置在哪些文字中进行识别
End Sub

Private Sub ListSame_Click() '点击List框,选择文字添加到文本框中
On Error Resume Next
TxtPrint.Text = Left(TxtPrint.Text, Len(TxtPrint.Text) - 1) & OcrText(ListSame.ListCount - ListSame.ListIndex).ModeText
End Sub

Private Sub PicPrint_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
If Button <> 0 Then
  If SapText.Visible = True Then Call CmdClear_Click '如果虚框在就将输入框清理了。
  PicPrint.Circle (x, y), 2 '进行绘图
End If
End Sub

  用户控件(UI)的实现:

  吴昊品工程级别软件项目 Round 3 —— 一个简易的字符识别系统(OCR技术+VB实现)

  这里的UI很精致啊!不是可以单靠属性框来实现的,需要再借助于编码来完成,UI编码如下:

  Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const WM_NCLBUTTONDOWN = &HA1
Private Const HTCAPTION = 2

Private Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function SetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Private Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long

Const RGN_OR = 2

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Private Type POINTAPI
        x As Long
        y As Long
End Type

Private Sub ImageL_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    If Button = 1 Then
    Call ReleaseCapture
    Call SendMessage(UserControl.Parent.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End If
End Sub

Private Sub ImageM_DblClick()

If PicMaxU.Enabled = True Then
    Call PicMaxU_Click
End If

End Sub

Private Sub ImageM_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    If Button = 1 Then
    Call ReleaseCapture
    Call SendMessage(UserControl.Parent.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End If
End Sub

Private Sub ImageR_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    If Button = 1 Then
    Call ReleaseCapture
    Call SendMessage(UserControl.Parent.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End If
End Sub

Private Sub LabelC_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    If Button = 1 Then
    Call ReleaseCapture
    Call SendMessage(UserControl.Parent.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End If
End Sub

Private Sub PicClose_Click()

End Sub

Private Sub PicCloseU_Click()
Unload UserControl.Parent
End Sub

Private Sub PicCloseU_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
    With PicCloseU
        If Button = 0 Then
            If (x < 0) Or (y < 0) Or (x > .Width) Or (y > .Height) Then
                ReleaseCapture ' 鼠标离开
                .Cls
            Else
                SetCapture .hwnd '鼠标进入
                BitBlt .hdc, 0, 0, 15, 16, PicClose.hdc, 0, 0, vbSrcCopy
                .Refresh
            End If
        End If
    End With
End Sub

Private Sub PicMax_Click()

End Sub

Private Sub PicMaxU_Click()
If UserControl.Parent.WindowState = 2 Then
    UserControl.Parent.WindowState = 0
Else
    UserControl.Parent.WindowState = 2
End If
PicMaxU.Cls
End Sub

Private Sub PicMaxU_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
    With PicMaxU
        If Button = 0 Then
            If (x < 0) Or (y < 0) Or (x > .Width) Or (y > .Height) Then
                ReleaseCapture ' 鼠标离开
                .Cls
            Else
                SetCapture .hwnd '鼠标进入
                
                BitBlt .hdc, 0, 0, 15, 16, PicMax.hdc, 0, 0, vbSrcCopy
                .Refresh
            End If
        End If
    End With
End Sub

Private Sub PicMin_Click()

End Sub

Private Sub PicMinU_Click()
UserControl.Parent.WindowState = 1
PicMinU.Cls
End Sub

Private Sub PicMinU_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
    With PicMinU
        If Button = 0 Then
            If (x < 0) Or (y < 0) Or (x > .Width) Or (y > .Height) Then
                ReleaseCapture ' 鼠标离开
                .Cls
            Else
                SetCapture .hwnd '鼠标进入
                BitBlt .hdc, 0, 0, 15, 16, PicMin.hdc, 0, 0, vbSrcCopy
                .Refresh
            End If
        End If
    End With
End Sub

Private Sub PicUn_Click()

End Sub

Private Sub UserControl_Resize()
On Error Resume Next
    ImageM.Width = UserControl.ScaleWidth - 14
    ImageR.Left = UserControl.ScaleWidth - 7
    UserControl.Height = 360
    UserControl.Width = UserControl.Parent.Width
    PicCloseU.Left = UserControl.ScaleWidth - 20
    PicMaxU.Left = UserControl.ScaleWidth - 43
    PicMinU.Left = UserControl.ScaleWidth - 67
    AllBlt UserControl.Parent, Picture000
    
    Dim Regn As Long
    Dim CER As Long
    'MakeNoBorderForm UserControl.Parent
    X1 = UserControl.Parent.Width / Screen.TwipsPerPixelX
    Y1 = UserControl.Parent.Height / Screen.TwipsPerPixelY
    
    Regn = CreateRectRgn(0, 4, X1, Y1)  '把句柄设为第一个矩形区域
    CER = CreateRectRgn(4, 0, X1 - 4, 10) '创建第二个矩形区域
    CombineRgn Regn, Regn, CER, RGN_OR   '把临时句柄变量或运算到句柄变量中
    CER = CreateRectRgn(2, 1, X1 - 2, 10)
    CombineRgn Regn, Regn, CER, RGN_OR   '把临时句柄变量或运算到句柄变量中
    CER = CreateRectRgn(1, 2, X1 - 1, 10)
    CombineRgn Regn, Regn, CER, RGN_OR   '把临时句柄变量或运算到句柄变量中
    Call SetWindowRgn(UserControl.Parent.hwnd, Regn, True) '创建窗体
    
    UserControl.Parent.Line (0, 21)-(0, UserControl.Parent.ScaleHeight - 1), 8684676
    UserControl.Parent.Line (0, UserControl.Parent.ScaleHeight - 1)-(UserControl.Parent.ScaleWidth - 1, UserControl.Parent.ScaleHeight - 1), 8684676
    UserControl.Parent.Line (UserControl.Parent.ScaleWidth - 1, 21)-(UserControl.Parent.ScaleWidth - 1, UserControl.Parent.ScaleHeight), 8684676

End Sub

Private Function AllBlt(frm As Object, Pic As Object)
Dim i As Long, j As Long
  frm.ScaleMode = 3
  frm.AutoRedraw = True
  Pic.AutoRedraw = True
  Pic.ScaleMode = 3
  Pic.AutoSize = True
  For i = 0 To frm.ScaleWidth Step Pic.ScaleWidth
    For j = 0 To frm.ScaleHeight Step Pic.ScaleHeight
      BitBlt frm.hdc, i, j, Pic.ScaleWidth, Pic.ScaleHeight, Pic.hdc, 0, 0, vbSrcCopy
    Next j
  Next i
  frm.Refresh
End Function

Private Sub MakeNoBorderForm(frm As Form)
'切除窗口的边框
Dim rctClient As RECT, rctFrame As RECT
Dim hRgn As Long
Dim lRes As Long
ReDim XY(3) As POINTAPI
Dim lpTL As POINTAPI, lpBR As POINTAPI
    
    '获得窗口矩形区域
    '将窗口矩形坐标转换为屏幕坐标
    lpTL.x = frm.Left / 15
    lpTL.y = frm.Top / 15
    ScreenToClient frm.hwnd, lpTL
    rctClient.Left = Abs(lpTL.x)
    rctClient.Top = Abs(lpTL.y)
    
    frm.ScaleMode = 1                                       'Twip
    
    rctClient.Right = frm.ScaleWidth / 15 + Abs(lpTL.x)
    rctClient.Bottom = frm.ScaleHeight / 15 + Abs(lpTL.y)
    
    '建立要切割的数组
    XY(0).x = rctClient.Left
    XY(0).y = rctClient.Top
    XY(1).x = rctClient.Right
    XY(1).y = rctClient.Top
    XY(2).x = rctClient.Right
    XY(2).y = rctClient.Bottom
    XY(3).x = rctClient.Left
    XY(3).y = rctClient.Bottom
     
    hRgn = CreatePolygonRgn(XY(0), 4, 2)
    lRes = SetWindowRgn(frm.hwnd, hRgn, True)
    
    frm.ScaleMode = 3
End Sub

Private Sub UserControl_Show()
If UserControl.Parent.MinButton = False Then
    BitBlt PicMinU.hdc, 0, 0, 15, 16, PicUn.hdc, 0, 0, vbSrcCopy
    PicMinU.Refresh
    PicMinU.Enabled = False
End If
    
If UserControl.Parent.MaxButton = False Then
    BitBlt PicMaxU.hdc, 0, 0, 15, 16, PicUn.hdc, 0, 0, vbSrcCopy
    PicMaxU.Refresh
    PicMaxU.Enabled = False
End If
LabelC.Caption = UserControl.Parent.Caption
ImageIco.Picture = UserControl.Parent.Icon

End Sub

  吴昊品工程级别软件项目 Round 3 —— 一个简易的字符识别系统(OCR技术+VB实现)

    对按钮的UI(这里也没有用VB6.0自带的默认按钮,不过,这里也需要写代码来对UI进行设计)

  Option Explicit

'Default Property Values:
Const m_def_TextAlign = vbCenter
Const m_def_PictureTColor = &HFF00FF
Const m_def_PicturePos = 0
Const m_def_TextColorDisabled2 = 0
Const m_def_DrawFocus = 0
Const m_def_DisplaceText = 0
Const m_def_TextLine = 1
'Const m_def_DownTextDX = 0
'Const m_def_DownTextDY = 0
Const m_def_DisableHover = False
Const m_def_TextColorEnabled = 0
Const m_def_TextColorDisabled = 0
Const m_def_FillWithColor = False
Const m_def_SizeCW = 12
Const m_def_SizeCH = 11
Const m_def_Text = ""
'Property Variables:
Dim m_TextAlign As AlignmentConstants
Dim m_PictureTColor As Ole_Color
Dim m_TextLine As Integer
Dim m_PicturePos As Integer
Dim m_Picture As StdPicture
Dim m_TextColorDisabled2 As Ole_Color
Dim m_DrawFocus As Integer
Dim m_DisplaceText As Integer
Dim m_DisableHover As Boolean
Dim m_TextColorEnabled As Ole_Color
Dim m_TextColorDisabled As Ole_Color
Dim m_FillWithColor As Boolean
Dim m_SizeCW As Long
Dim m_SizeCH As Long
Dim m_SkinPicture As PictureBox
Dim m_Text As String
Dim m_State As Integer
Dim m_HasFocus As Boolean
Dim m_BtnDown As Boolean
Dim m_SpcDown As Boolean
Dim m_SkinPictureName As String


Public Enum EnumPicturePos
    ppLeft
    ppTop
    ppBottom
    ppRight
    ppCenter
End Enum
Private Const DI_NORMAL As Long = &H3

Const BTN_NORMAL = 1
Const BTN_FOCUS = 2
Const BTN_HOVER = 3
Const BTN_DOWN = 4
Const BTN_DISABLED = 5
'Event Declarations:
Event Click() 'MappingInfo=UserControl,UserControl,-1,Click
Event MouseHover()
Event MouseOut()
Event MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
Event MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
Event MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
Event KeyPress(KeyAscii As Integer)
Event KeyDown(KeyCode As Integer, Shift As Integer)
Event KeyUp(KeyCode As Integer, Shift As Integer)

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Public Enum EnumDrawTextFormat
    DT_BOTTOM = &H8
    DT_CALCRECT = &H400
    DT_CENTER = &H1
    DT_CHARSTREAM = 4
    DT_DISPFILE = 6
    DT_EXPANDTABS = &H40
    DT_EXTERNALLEADING = &H200
    DT_INTERNAL = &H1000
    DT_LEFT = &H0
    DT_METAFILE = 5
    DT_NOCLIP = &H100
    DT_NOPREFIX = &H800
    DT_PLOTTER = 0
    DT_RASCAMERA = 3
    DT_RASDISPLAY = 1
    DT_RASPRINTER = 2
    DT_RIGHT = &H2
    DT_SINGLELINE = &H20
    DT_TABSTOP = &H80
    DT_TOP = &H0
    DT_VCENTER = &H4
    DT_WORDBREAK = &H10
    DT_WORD_ELLIPSIS = &H40000
    DT_END_ELLIPSIS = 32768
    DT_PATH_ELLIPSIS = &H4000
    DT_EDITCONTROL = &H2000
    '===================
    DT_INCENTER = DT_CENTER Or DT_VCENTER Or DT_SINGLELINE
End Enum

Private Const SRCCOPY = &HCC0020
Private Const RGN_AND = 1

Private Declare Function BeginPath Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function EndPath Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function Rectangle Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function SelectClipPath Lib "gdi32" (ByVal hdc As Long, ByVal iMode As Long) As Long
Private Declare Function SelectClipRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Declare Function apiDrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function apiTranslateColor Lib "olepro32.dll" Alias "OleTranslateColor" (ByVal clr As Ole_Color, ByVal palet As Long, Col As Long) As Long
Private Declare Function DrawFocusRect Lib "user32" (ByVal hdc As Long, lpRect As RECT) As Long
Private Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
'Private Declare Function TransparentBlt Lib "msimg32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean
'MY NOTE: TransparentBlt on Win98 leavs some garbage in memory...
'
'Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GdiTransparentBlt Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean
Private Declare Function DrawIcon Lib "user32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal hIcon As Long) As Long
Private Declare Function SetDIBColorTable Lib "gdi32" (ByVal hdc As Long, ByVal un1 As Long, ByVal un2 As Long, pcRGBQuad As RGBQUAD) As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long

'for picture
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
'Private Declare Function DrawIcon Lib "user32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal hIcon As Long) As Long
'Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As BITMAPINFO, ByVal un As Long, ByVal lplpVoid As Long, ByVal handle As Long, ByVal dw As Long) As Long
Private Declare Function RealizePalette Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, ByVal cxWidth As Long, ByVal cyWidth As Long, ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long
Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long
'never enough
Private Declare Function GetBkColor Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetTextColor Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SetBkColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Private Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long


Private Type BITMAPINFOHEADER
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As Long
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
End Type
Private Type RGBQUAD
        rgbBlue As Byte
        rgbGreen As Byte
        rgbRed As Byte
        rgbReserved As Byte
End Type
Private Type BITMAP
        bmType As Long
        bmWidth As Long
        bmHeight As Long
        bmWidthBytes As Long
        bmPlanes As Integer
        bmBitsPixel As Integer
        bmBits As Long
End Type
Private Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        bmiColors(1) As RGBQUAD
End Type

'windows version
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long



'#############################################
'//GDI + SOMETHING ELSE#######################
Private Sub TransBlt(ByVal hdcDest As Long, ByVal xDest As Long, ByVal yDest As Long, _
            ByVal nWidth As Long, ByVal nHeight As Long, ByVal hdcSrc As Long, _
            ByVal xSrc As Long, ByVal ySrc As Long, ByVal clrMask As Ole_Color)
    
'one check to see if GdiTransparentblt is supported
'better way to check if function is suported is using LoadLibrary and GetProcAdress
'than using GetVersion or GetVersionEx
'=====================================================
    Dim Lib As Long
    Dim ProcAdress As Long
    Dim lMaskColor As Long
    lMaskColor = TranslateColor(clrMask)
    Lib = LoadLibrary("gdi32.dll")
    '-------------------------------->make sure to specify corect name for function
    ProcAdress = GetProcAddress(Lib, "GdiTransparentBlt")
    FreeLibrary Lib
    If ProcAdress <> 0 Then
        'works on XP
        GdiTransparentBlt hdcDest, xDest, yDest, nWidth, nHeight, hdcSrc, xSrc, ySrc, nWidth, nHeight, lMaskColor
        'Debug.Print "Gdi transparent blt"
        Exit Sub 'make it short
    End If
'=====================================================
    Const DSna              As Long = &H220326
    Dim hdcMask             As Long
    Dim hdcColor            As Long
    Dim hbmMask             As Long
    Dim hbmColor            As Long
    Dim hbmColorOld         As Long
    Dim hbmMaskOld          As Long
    Dim hdcScreen           As Long
    Dim hdcScnBuffer        As Long
    Dim hbmScnBuffer        As Long
    Dim hbmScnBufferOld     As Long
    

   hdcScreen = UserControl.hdc
   
   lMaskColor = TranslateColor(clrMask)
   hbmScnBuffer = CreateCompatibleBitmap(hdcScreen, nWidth, nHeight)
   hdcScnBuffer = CreateCompatibleDC(hdcScreen)
   hbmScnBufferOld = SelectObject(hdcScnBuffer, hbmScnBuffer)

   BitBlt hdcScnBuffer, 0, 0, nWidth, nHeight, hdcDest, xDest, yDest, vbSrcCopy

   hbmColor = CreateCompatibleBitmap(hdcScreen, nWidth, nHeight)
   hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ByVal 0&)

   hdcColor = CreateCompatibleDC(hdcScreen)
   hbmColorOld = SelectObject(hdcColor, hbmColor)
    
   Call SetBkColor(hdcColor, GetBkColor(hdcSrc))
   Call SetTextColor(hdcColor, GetTextColor(hdcSrc))
   Call BitBlt(hdcColor, 0, 0, nWidth, nHeight, hdcSrc, xSrc, ySrc, vbSrcCopy)

   hdcMask = CreateCompatibleDC(hdcScreen)
   hbmMaskOld = SelectObject(hdcMask, hbmMask)

   SetBkColor hdcColor, lMaskColor
   SetTextColor hdcColor, vbWhite
   BitBlt hdcMask, 0, 0, nWidth, nHeight, hdcColor, 0, 0, vbSrcCopy
 
   SetTextColor hdcColor, vbBlack
   SetBkColor hdcColor, vbWhite
   BitBlt hdcColor, 0, 0, nWidth, nHeight, hdcMask, 0, 0, DSna
   BitBlt hdcScnBuffer, 0, 0, nWidth, nHeight, hdcMask, 0, 0, vbSrcAnd
   BitBlt hdcScnBuffer, 0, 0, nWidth, nHeight, hdcColor, 0, 0, vbSrcPaint
   BitBlt hdcDest, xDest, yDest, nWidth, nHeight, hdcScnBuffer, 0, 0, vbSrcCopy
     
     'clear
   DeleteObject SelectObject(hdcColor, hbmColorOld)
   DeleteDC hdcColor
   DeleteObject SelectObject(hdcScnBuffer, hbmScnBufferOld)
   DeleteDC hdcScnBuffer
   DeleteObject SelectObject(hdcMask, hbmMaskOld)
   
   DeleteDC hdcMask
   'ReleaseDC 0, hdcScreen
End Sub

Private Function GetRgbQuad(ByVal R As Byte, ByVal G As Byte, ByVal B As Byte) As RGBQUAD
    With GetRgbQuad
        .rgbBlue = B
        .rgbGreen = G
        .rgbRed = R
    End With
End Function
Private Function DrawPictureDisabled(ByVal P As StdPicture, x As Long, y As Long, _
                 w As Long, h As Long, _
                 Optional ColHighlight As Long = vb3DHighlight, _
                 Optional ColShadow As Long = vb3DShadow)
                 
    Dim MemDC As Long
    Dim MyBmp As Long
    Dim cShadow As Long
    Dim cHiglight As Long
    Dim ColPal(0 To 1) As RGBQUAD
    Dim rgbBlack As RGBQUAD
    Dim rgbWhite As RGBQUAD
    Dim BI As BITMAPINFO
    Dim hdc As Long
    Dim hPicDc As Long
    Dim hPicBmp As Long
    hdc = UserControl.hdc
    
    cHiglight = TranslateColor(vb3DHighlight)
    cShadow = TranslateColor(vb3DShadow)
    
    'rgbBlack = GetRgbQuad(0, 0, 0)
    rgbWhite = GetRgbQuad(255, 255, 255)
    
    With BI.bmiHeader
        .biSize = 40 'size of bmiHeader structure
        .biHeight = -h
        .biWidth = w
        .biPlanes = 1
        .biCompression = 0 'BI_RGB
        .biClrImportant = 0
        .biBitCount = 1 'monohrome bitmap
    End With
    
    'color palete
    With BI
        .bmiColors(0) = rgbBlack
        .bmiColors(1) = rgbWhite
    End With
    
    Dim hMonoSec As Long
    Dim pBits As Long
    Dim hdcMono As Long
    
    hMonoSec = CreateDIBSection(hdc, BI, 0, pBits, 0&, 0&)
    'Debug.Print "MonoSec:"; hMonoSec
    hdcMono = CreateCompatibleDC(hdc)
    SelectObject hdcMono, hMonoSec
    
    'create dc for picture
    hPicDc = CreateCompatibleDC(hdc)
    If P.Type = vbPicTypeIcon Then
        hPicBmp = CreateCompatibleBitmap(hdc, w, h)
        SelectObject hPicDc, hPicBmp
        DeleteObject hPicBmp
        ClearRect hPicDc, SetRect(0, 0, w, h), TranslateColor(m_PictureTColor)
        DrawIconEx hPicDc, 0, 0, P.handle, w, h, 0, 0, DI_NORMAL
        'Debug.Print "DRAW ICON"
    ElseIf P.Type = vbPicTypeBitmap Then
        SelectObject hPicDc, P.handle
    End If
    
    'copy  hPicDc to hdcMono
    BitBlt hdcMono, 0, 0, w, h, hPicDc, 0, 0, SRCCOPY
    
    DeleteDC hPicDc
    
    Dim R As Integer, G As Integer, B   As Integer
    GetRgb cHiglight, R, G, B
    
    'change black color in palete to highlight(r,g,b) color
    ColPal(0) = GetRgbQuad(R, G, B)
    ColPal(1) = rgbBlack    'change white color in palete to black color
    
    SetDIBColorTable hdcMono, 0, 2, ColPal(0)   'set new palete
    RealizePalette hdcMono                      'update it
    'BitBlt Me.hdc, 1, 1, W, H, hdcMono,  0, 0, SRCCOPY
      
    'transparent blit to dest hDC using black as transparent colour
    'x+1 and y+1 - moves down and left for 1 pixel
    TransBlt hdc, x + 1, y + 1, w, h, hdcMono, 0, 0, 0
    
    'get rgb components of shadow color
    GetRgb cShadow, R, G, B
    'change black color to shadow color in palete
    ColPal(0) = GetRgbQuad(R, G, B)
    ColPal(1) = rgbWhite 'change back to white
    
    'set new palete
    SetDIBColorTable hdcMono, 0, 2, ColPal(0)
    RealizePalette hdcMono ' then update
    
    'transparent blit do dest hdc using white color as transparent
    TransBlt hdc, x, y, w, h, hdcMono, 0, 0, #ffffff
    
    'BitBlt Me.hDC, 0, 0, W, H, hdcMono, 0, 0, SRCCOPY
    
    'Debug.Print DeleteObject(hMonoSec)
    'Debug.Print DeleteObject(hdcMono)
   
End Function
Sub GetRgb(Color As Long, R As Integer, G As Integer, B As Integer)
       R = Color And 255            'clear bites from 9 to 32
       G = (Color \ 256) And 255    'shift right 8 bits and clear
       B = (Color \ 65536) And 255  'shift 16 bits and clear for any case
End Sub

Private Function GetBmpSize(Bmp As StdPicture, w As Long, h As Long) As Long
'    Dim B As BITMAP
'    GetBmpSize = GetObject(Bmp, Len(B), B)
    
    w = ScaleX(Bmp.Width, vbHimetric, vbPixels)
    h = ScaleY(Bmp.Height, vbHimetric, vbPixels)
        
'    Debug.Print W, H
    
    
'    W = B.bmWidth
'    H = B.bmHeight
'    Debug.Print B.bmType
'    Debug.Print W, H
End Function

Private Sub DrawPicture(hdc As Long, P As StdPicture, x As Long, y As Long, w As Long, h As Long, TOleCol As Long)
    
    'check picture format
    If P.Type = vbPicTypeIcon Then
        DrawIconEx hdc, x, y, P.handle, w, h, 0, 0, DI_NORMAL
        Exit Sub
    End If
    
    'creting dc with the same format as screen dc
    Dim MemDC As Long
    MemDC = CreateCompatibleDC(0)
    
    'select a picture into memdc
    SelectObject MemDC, P.handle '
    
    'tranparent blit memdc on usercontrol
    TransBlt UserControl.hdc, x, y, w, h, MemDC, 0, 0, TranslateColor(TOleCol)
    
    DeleteDC MemDC 'its clear, heh
End Sub


Private Function ModifyRect(lpRect As RECT, ByVal Left As Long, ByVal Top As Long, _
               ByVal Right As Long, ByVal Bottom As Long) As RECT
    With ModifyRect
        .Left = lpRect.Left + Left
        .Top = lpRect.Top + Top
        .Right = lpRect.Right + Right
        .Bottom = lpRect.Bottom + Bottom
    End With
End Function
Private Function TranslateColor(ByVal Ole_Color As Long) As Long
        apiTranslateColor Ole_Color, 0, TranslateColor
End Function
Private Function SetRect(ByVal Left As Long, ByVal Top As Long, ByVal Right As Long, ByVal Bottom As Long) As RECT
  With SetRect
    .Left = Left
    .Top = Top
    .Right = Right
    .Bottom = Bottom
  End With
End Function
Private Sub NormalizeRect(R As RECT)
    Dim c As Long
    If R.Left > R.Right Then
        c = R.Right
        R.Right = R.Left
        R.Left = c
    End If
    If R.Top > R.Bottom Then
        c = R.Top
        R.Top = R.Bottom
        R.Bottom = c
    End If
End Sub
Private Function RoundUp(ByVal num As Single) As Long
    If Int(num) < num Then
        RoundUp = Int(num) + 1
    Else
        RoundUp = num
    End If
End Function
Private Function RectHeight(R As RECT) As Long
    RectHeight = R.Bottom - R.Top
End Function
Private Function RectWidth(R As RECT) As Long
    RectWidth = R.Right - R.Left
End Function

Function TxtFix(StrText As String, MaxWidth As Long) As String
Dim i As Long, j As Long
Dim StrLeft As String, TxtTemp As String
TxtTemp = StrText
TxtFix = ""
For i = Len(TxtTemp) To 1 Step -1
  For j = Len(TxtTemp) To 1 Step -1
    If UserControl.TextWidth(Left(TxtTemp, j)) <= MaxWidth Then
      StrLeft = Left(TxtTemp, j)
      TxtTemp = Right(TxtTemp, Len(TxtTemp) - j)
      If TxtFix = "" Then
        TxtFix = StrLeft
      Else
        TxtFix = TxtFix & vbCrLf & StrLeft
      End If
      Exit For
    End If
  Next j
Next i
End Function

Private Sub DrawText(ByVal hdc As Long, ByVal StrText As String, R As RECT, ByVal Format As Long)
Dim TempText As String, TempHeight As Long, TempTop As Long, Rc As RECT
TempText = TxtFix(StrText, R.Right - R.Left)
TempHeight = UserControl.TextHeight(TempText)
TempTop = R.Top - (R.Top - R.Bottom) / 2 - TempHeight / 2
Rc = SetRect(R.Left, TempTop, R.Right, TempTop + TempHeight)
With UserControl
    apiDrawText .hdc, StrText, lstrlen(StrText), Rc, Format
End With
End Sub

Private Sub TilePicture(DestRect As RECT, SrcRect As RECT, ByVal SrcDc As Long, Optional UseCliper As Boolean = True, Optional ROp As Long = SRCCOPY)
    
    Dim i As Integer
    Dim j As Integer
    Dim rows As Integer
    Dim ColS As Integer
    Dim destW As Long
    Dim destH As Long
    Dim hdc As Long
    hdc = UserControl.hdc
    
    NormalizeRect DestRect
    NormalizeRect SrcRect
       
    'calculates row and cols
    rows = RoundUp(RectHeight(DestRect) / RectHeight(SrcRect))
    ColS = RoundUp(RectWidth(DestRect) / RectWidth(SrcRect))
    
    destW = RectWidth(SrcRect)
    destH = RectHeight(SrcRect)
   
    'prevents drawing out of specified rectangle
    If UseCliper Then
        SelectClipRgn hdc, ByVal 0
        BeginPath hdc
            With DestRect
                 Rectangle hdc, .Left, .Top, .Right + 1, .Bottom + 1
            End With
        EndPath hdc
        SelectClipPath hdc, RGN_AND
    End If
    
    For i = 0 To rows - 1
        For j = 0 To ColS - 1
            BitBlt hdc, j * destW + DestRect.Left, i * destH + DestRect.Top, destW, destH, SrcDc, _
            SrcRect.Left, SrcRect.Top, ROp
        Next
    Next
    
    If UseCliper Then
        SelectClipRgn hdc, ByVal 0
    End If
End Sub

Private Sub ClearRect(ByVal hdc As Long, lRect As RECT, ByVal Color As Long)
    Dim Brush As Long
    Dim PBrush As Long
    Brush = CreateSolidBrush(Color)
    PBrush = SelectObject(hdc, Brush)
    
    FillRect hdc, lRect, Brush
    DeleteObject SelectObject(hdc, PBrush)
End Sub
'//END GDI####################################
'#############################################

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,3
Public Property Get SizeCW() As Long
    SizeCW = m_SizeCW
End Property

Public Property Let SizeCW(ByVal New_SizeCW As Long)
        m_SizeCW = New_SizeCW
        PropertyChanged "SizeCW"
        Refresh
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,3
Public Property Get SizeCH() As Long
    SizeCH = m_SizeCH
End Property

Public Property Let SizeCH(ByVal New_SizeCH As Long)
        m_SizeCH = New_SizeCH
        PropertyChanged "SizeCH"
        Refresh
End Property

Public Property Get TextLine() As Integer
    TextLine = m_TextLine
End Property

Public Property Let TextLine(ByVal New_TextLine As Integer)
        m_TextLine = New_TextLine
        PropertyChanged "TextLine"
        Refresh
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=9,0,0,0
Public Property Get SkinPicture() As Object
    Set SkinPicture = m_SkinPicture
End Property

Public Property Set SkinPicture(New_SkinPicture As Object)
    
    
    If (TypeName(New_SkinPicture) <> "PictureBox") And _
       (New_SkinPicture Is Nothing = False) Then
        
        Err.Raise 5, "MyButton::SkinPicture", Err.Description
        Exit Property
    End If
               
    Set m_SkinPicture = New_SkinPicture
    
    If m_SkinPicture Is Nothing = False Then
        m_SkinPictureName = m_SkinPicture.Name
    Else
        m_SkinPictureName = ""
    End If
    
    Refresh
    PropertyChanged "SPN"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=13,0,0,
Public Property Get Text() As String
    Text = m_Text
End Property

Public Property Let Text(ByVal New_Text As String)
    m_Text = New_Text
    Refresh
    PropertyChanged "Text"
    
    'setting access key (allows alt + accesskey)
    
    Dim i As Long
    Dim c As String
    
    For i = 1 To Len(New_Text) - 1
        If Mid(New_Text, i, 1) = "&" Then
            c = Mid(New_Text, i + 1, 1)
            If c <> "&" Or c <> " " Then
                UserControl.AccessKeys = c
                PropertyChanged "AccessKey"
            End If
        End If
        
    Next
   
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=13,0,0,
Public Property Get SkinPictureName() As String
    'If m_SkinPicture Is Nothing = False Then
        'SkinPictureName = m_SkinPicture.Name
        SkinPictureName = m_SkinPictureName
    'End If
End Property

Public Property Let SkinPictureName(ByVal New_SkinPictureName As String)
    On Error GoTo NotLegalName
    Dim P As Object
    'Debug.Print New_SkinPictureName
    If New_SkinPictureName <> "" Then
        
        Set P = UserControl.Parent.Controls(New_SkinPictureName)
        
        If P Is Nothing = False Then
            Set SkinPicture = P
            'Debug.Print "Setting p"; P.Name
        End If
    Else
        Set m_SkinPicture = Nothing
        'Debug.Print "P is nothing"
        Refresh
    End If
   
'    m_SkinPictureName = New_SkinPictureName
    PropertyChanged "SPN"
NotLegalName:
End Property

Private Sub UserControl_DblClick()
    DrawButton BTN_DOWN
End Sub

Private Sub UserControl_GotFocus()
    m_HasFocus = True
    If m_BtnDown = False Then DrawButton BTN_FOCUS
End Sub

Private Sub UserControl_Initialize()
'    SkinPictureName = m_SkinPictureName
'    MsgBox "Initialize..." + m_SkinPictureName
End Sub

'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
    m_SizeCW = m_def_SizeCW
    m_SizeCH = m_def_SizeCH
    m_Text = Extender.Name
    m_FillWithColor = m_def_FillWithColor
    m_TextColorEnabled = m_def_TextColorEnabled
    m_TextColorDisabled = m_def_TextColorDisabled
    Set UserControl.Font = Ambient.Font
    m_DisableHover = m_def_DisableHover

    m_DisplaceText = m_def_DisplaceText
    m_TextLine = m_def_TextLine
    m_DrawFocus = m_def_DrawFocus
    m_TextColorDisabled2 = m_def_TextColorDisabled2
    Set m_Picture = LoadPicture("")
    m_PicturePos = m_def_PicturePos
    m_PictureTColor = m_def_PictureTColor
    m_SkinPictureName = "MyButtonDefSkin"
    m_TextAlign = m_def_TextAlign
End Sub

Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)
    RaiseEvent KeyDown(KeyCode, Shift)
    
    If KeyCode = vbKeySpace Then
        m_SpcDown = True
        DrawButton BTN_DOWN
    Else
        m_SpcDown = False
        DrawButton BTN_FOCUS
    End If
End Sub

Private Sub UserControl_KeyPress(KeyAscii As Integer)
    RaiseEvent KeyPress(KeyAscii)
    
    If KeyAscii = vbKeyReturn Then
        RaiseEvent Click
    End If
End Sub

Private Sub UserControl_KeyUp(KeyCode As Integer, Shift As Integer)
    RaiseEvent KeyUp(KeyCode, Shift)
    If KeyCode = 32 And m_SpcDown And m_State = BTN_DOWN Then
        m_SpcDown = False
        
        DrawButton BTN_NORMAL
        RaiseEvent Click
        DrawButton BTN_FOCUS
        
    End If
End Sub

Private Sub UserControl_LostFocus()
    m_HasFocus = False
    DrawButton BTN_NORMAL
End Sub

Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
   RaiseEvent MouseDown(Button, Shift, x, y)
   If Button = 1 Then m_BtnDown = True
   UserControl_MouseMove Button, Shift, x, y
End Sub

Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
    If m_SpcDown Then Exit Sub
    
    RaiseEvent MouseMove(Button, Shift, x, y)
    SetCapture hwnd
    If PointInControl(x, y) Then
        'if pointer is on control
        If m_BtnDown Then
            If m_State <> BTN_DOWN Then
                DrawButton BTN_DOWN
            End If
        Else
            If m_State <> BTN_HOVER Then
                RaiseEvent MouseHover
                DrawButton BTN_HOVER
            End If
            
        End If
    Else
        'if pointer is out of control
        If m_BtnDown Then
            
            RaiseEvent MouseHover
            DrawButton BTN_HOVER
            
        Else
            RaiseEvent MouseOut
            If m_HasFocus Then
                DrawButton BTN_FOCUS
            Else
                DrawButton BTN_NORMAL
            End If
            ReleaseCapture
        End If
    End If
End Sub

Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
    
    m_BtnDown = False
'    If m_State <> BTN_NORMAL Then
        DrawButton BTN_NORMAL
'    End If
    
    RaiseEvent MouseUp(Button, Shift, x, y)
    
    If Button = vbLeftButton Then
        If PointInControl(x, y) Then RaiseEvent Click
'        If m_State <> BTN_FOCUS Then
            DrawButton BTN_FOCUS
'        End If
    End If
    
End Sub


Private Sub UserControl_Paint()
    Me.Refresh
End Sub

'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    m_SizeCW = PropBag.ReadProperty("SizeCW", m_def_SizeCW)
    m_SizeCH = PropBag.ReadProperty("SizeCH", m_def_SizeCH)
    m_SkinPictureName = PropBag.ReadProperty("SPN", "")
   
    'Debug.Print "ReadProp SPN:"; m_SkinPictureName
    m_TextLine = PropBag.ReadProperty("TextLine", m_def_TextLine)
    m_Text = PropBag.ReadProperty("Text", m_def_Text)
    m_FillWithColor = PropBag.ReadProperty("FillWithColor", m_def_FillWithColor)
    UserControl.Enabled = PropBag.ReadProperty("Enabled", True)
    UserControl.AccessKeys = PropBag.ReadProperty("AccessKey", "")
    m_TextColorEnabled = PropBag.ReadProperty("TextColorEnabled", m_def_TextColorEnabled)
    m_TextColorDisabled = PropBag.ReadProperty("TextColorDisabled", m_def_TextColorDisabled)
    Set UserControl.Font = PropBag.ReadProperty("Font", Ambient.Font)
    UserControl.MousePointer = PropBag.ReadProperty("MousePointer", 0)
    Set MouseIcon = PropBag.ReadProperty("MouseIcon", Nothing)
    m_DisableHover = PropBag.ReadProperty("DisableHover", m_def_DisableHover)
'    m_DownTextDX = PropBag.ReadProperty("DownTextDX", m_def_DownTextDX)
'    m_DownTextDY = PropBag.ReadProperty("DownTextDY", m_def_DownTextDY)
    m_DisplaceText = PropBag.ReadProperty("DisplaceText", m_def_DisplaceText)
    m_DrawFocus = PropBag.ReadProperty("DrawFocus", m_def_DrawFocus)
    m_TextColorDisabled2 = PropBag.ReadProperty("TextColorDisabled2", m_def_TextColorDisabled2)
    Set m_Picture = PropBag.ReadProperty("Picture", Nothing)
    m_PicturePos = PropBag.ReadProperty("PicturePos", m_def_PicturePos)
    m_PictureTColor = PropBag.ReadProperty("PictureTColor", m_def_PictureTColor)
    m_TextAlign = PropBag.ReadProperty("TextAlign", m_def_TextAlign)
    UserControl.BackColor = PropBag.ReadProperty("BackColor", &H8000000F)
End Sub

Private Sub UserControl_Resize()
    Refresh
End Sub

Private Sub UserControl_Show()
    
    SkinPictureName = m_SkinPictureName

   ' Refresh
End Sub

Private Sub UserControl_Terminate()
    Set m_SkinPicture = Nothing
    Set m_Picture = Nothing
    
    'Set UserControl = Nothing
    'Set Me = Nothing
    'Debug.Print "TERMINATE"
End Sub

'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    Call PropBag.WriteProperty("SizeCW", m_SizeCW, m_def_SizeCW)
    Call PropBag.WriteProperty("SizeCH", m_SizeCH, m_def_SizeCH)
    
    'If m_SkinPicture Is Nothing = False Then
        Call PropBag.WriteProperty("SPN", m_SkinPictureName, "")
    'End If
    
    'Debug.Print "Write :"; m_SkinPictureName
    Call PropBag.WriteProperty("TextLine", m_def_TextLine)
    Call PropBag.WriteProperty("Text", m_Text, m_def_Text)
    Call PropBag.WriteProperty("FillWithColor", m_FillWithColor, m_def_FillWithColor)
    Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)
    Call PropBag.WriteProperty("AccessKey", UserControl.AccessKeys, "")
    Call PropBag.WriteProperty("TextColorEnabled", m_TextColorEnabled, m_def_TextColorEnabled)
    Call PropBag.WriteProperty("TextColorDisabled", m_TextColorDisabled, m_def_TextColorDisabled)
    Call PropBag.WriteProperty("Font", UserControl.Font, Ambient.Font)

    Call PropBag.WriteProperty("MousePointer", UserControl.MousePointer, 0)
    Call PropBag.WriteProperty("MouseIcon", MouseIcon, Nothing)
    Call PropBag.WriteProperty("DisableHover", m_DisableHover, m_def_DisableHover)
    Call PropBag.WriteProperty("DisplaceText", m_DisplaceText, m_def_DisplaceText)
    Call PropBag.WriteProperty("DrawFocus", m_DrawFocus, m_def_DrawFocus)
    Call PropBag.WriteProperty("TextColorDisabled2", m_TextColorDisabled2, m_def_TextColorDisabled2)
    Call PropBag.WriteProperty("Picture", m_Picture, Nothing)
    Call PropBag.WriteProperty("PicturePos", m_PicturePos, m_def_PicturePos)
    Call PropBag.WriteProperty("PictureTColor", m_PictureTColor, m_def_PictureTColor)
    Call PropBag.WriteProperty("TextAlign", m_TextAlign, m_def_TextAlign)
    Call PropBag.WriteProperty("BackColor", UserControl.BackColor, &H8000000F)
End Sub


Private Sub DrawButton(ByVal State As Integer)
    
    If m_DisableHover Then
        If State = BTN_HOVER Then Exit Sub
        'dont draw hover state if m_DisableHover is true
    End If
'    Debug.Print "State1 "; State

    On Error GoTo UnknownError

    Dim PicW As Long
    Dim PicH As Long 'width and height of picture

    Dim PicX As Long
    Dim PicY As Long 'picture pos

    Dim DH As Long  'button height
    Dim dw As Long  'button width
    Dim Align As Long 'text aligment
    Dim bDrawText As Boolean ' if picture is in center text is not drawn
    bDrawText = True

    Align = DT_VCENTER Or DT_END_ELLIPSIS Or DT_WORDBREAK

    Select Case m_TextAlign
        Case Is = vbLeftJustify:  Align = Align Or DT_LEFT
        Case Is = vbRightJustify: Align = Align Or DT_RIGHT
        Case Is = vbCenter:       Align = Align Or DT_CENTER
    End Select

    dw = UserControl.ScaleWidth
    DH = UserControl.ScaleHeight

    m_State = State
    'if skin picture is not set then just draw text on control
    If m_SkinPicture Is Nothing Then
        ClearRect hdc, SetRect(0, 0, dw, DH), TranslateColor(UserControl.BackColor)
        DrawText hdc, m_Text, SetRect(0, 0, dw, DH), Align
        If UserControl.AutoRedraw = True Then
            UserControl.Refresh
        End If
        Exit Sub
    End If


    m_SkinPicture.ScaleMode = vbPixels


    Dim SrcLeft As Long     'left cordinate of skin in skinpicture
    Dim SrcRight As Long    'right -II-
    Dim FillColor As Long   'color to fill middle area of button
                            'used if m_FillWithColor is true

    Dim h As Long           'height of skinpicture
    Dim w As Long           'width of button skin

    h = m_SkinPicture.ScaleHeight
    w = m_SkinPicture.ScaleWidth / 5
'Debug.Print H, W
'
    SrcLeft = (State - 1) * w
    SrcRight = State * w

    If m_FillWithColor Then
        'get color to fill with from (SrcLeft+m_SizeCW +1 , m_SizeCH+1) on
        'skin picture
        FillColor = m_SkinPicture.Point(SrcLeft + m_SizeCW + 1, m_SizeCH + 1)
    End If

'Exit Sub
    ClearRect hdc, SetRect(0, 0, dw, DH), TranslateColor(UserControl.BackColor)
    If m_FillWithColor Then
        'paint button with fillcolor
        'NOTE: it would be nice if there is gradient file
        ClearRect hdc, SetRect(m_SizeCW, m_SizeCH, dw - m_SizeCW, DH - m_SizeCH), FillColor
        'ABOUT ADDING GRADIENT FILL
        'read second color from skin at
        'point (srcleft+cw+1, H -m_sizeCH-1)
        'may be implemented in MyButton2
    Else
        'tile skin
         TilePicture SetRect(m_SizeCW, m_SizeCH, dw - m_SizeCW, DH - m_SizeCH), _
           SetRect(SrcLeft + m_SizeCW, m_SizeCH, SrcRight - m_SizeCW, h - m_SizeCH), _
           m_SkinPicture.hdc, False, SRCCOPY
    End If

    'draws borders
    If (m_SizeCH > 0 And m_SizeCW > 0) Then
        TilePicture SetRect(m_SizeCW, 0, dw, m_SizeCH), _
            SetRect(SrcLeft + m_SizeCW, 0, SrcRight - m_SizeCW, m_SizeCH), _
            m_SkinPicture.hdc, False, SRCCOPY

        TilePicture SetRect(m_SizeCW, DH - m_SizeCH, dw, DH), _
            SetRect(SrcLeft + m_SizeCW, h - m_SizeCH, SrcRight - m_SizeCW, h), _
            m_SkinPicture.hdc, False, SRCCOPY

        TilePicture SetRect(0, 0, m_SizeCW, DH), _
            SetRect(SrcLeft, m_SizeCH, SrcLeft + m_SizeCW, h - m_SizeCH), _
            m_SkinPicture.hdc, False, SRCCOPY

        TilePicture SetRect(dw - m_SizeCW, m_SizeCH, dw, DH - m_SizeCH), _
            SetRect(SrcRight - m_SizeCW, m_SizeCH, SrcRight, h - m_SizeCH), _
            m_SkinPicture.hdc, False, SRCCOPY

        'draws corners
        'NOTE: must chage to transparent blit (done)
        TransBlt hdc, 0, 0, m_SizeCW, m_SizeCH, m_SkinPicture.hdc, SrcLeft, 0, &HFF00FF
        TransBlt hdc, 0, DH - m_SizeCH, m_SizeCW, m_SizeCH, m_SkinPicture.hdc, SrcLeft, h - m_SizeCH, &HFF00FF

        TransBlt hdc, dw - m_SizeCW, 0, m_SizeCW, m_SizeCH, m_SkinPicture.hdc, SrcRight - m_SizeCW, 0, &HFF00FF
        TransBlt hdc, dw - m_SizeCW, DH - m_SizeCH, m_SizeCW, m_SizeCH, m_SkinPicture.hdc, SrcRight - m_SizeCW, h - m_SizeCH, &HFF00FF
    End If

    Dim Pcolor As Long 'previous color

    Pcolor = UserControl.ForeColor

    Dim TextRect As RECT
    If State = BTN_DOWN Then
        TextRect = SetRect(3 + m_DisplaceText, 3 + m_DisplaceText, dw - 3 + m_DisplaceText - 3, DH - 3 + m_DisplaceText)
    Else
        TextRect = SetRect(3, 3, dw - 3 - 3, DH - 3)
    End If
        If m_Picture Is Nothing Then
            If m_State = BTN_DISABLED Then
                'draw text only
                'dont draw text2 if colors are the same
                If m_TextColorDisabled <> m_TextColorDisabled2 Then
                    UserControl.ForeColor = m_TextColorDisabled2
                    TextRect = ModifyRect(TextRect, 1, 1, 1, 1)
                    DrawText hdc, m_Text, TextRect, Align
                    TextRect = ModifyRect(TextRect, -1, -1, -1, -1)
                End If
                UserControl.ForeColor = m_TextColorDisabled
                DrawText hdc, m_Text, TextRect, Align
            Else
                'draw text only
                UserControl.ForeColor = m_TextColorEnabled
                DrawText hdc, m_Text, TextRect, Align
            End If
        Else

            GetBmpSize m_Picture, PicW, PicH
            PicY = (DH - PicH) / 2
            If m_State = BTN_DOWN Then
                PicY = PicY + m_DisplaceText
            End If



            Select Case m_PicturePos
                Case Is = ppLeft
                    PicX = TextRect.Left + 3
                    TextRect.Left = PicX + PicW + TextRect.Left
                Case Is = ppRight
                    PicX = TextRect.Right - PicW - 3 + TextRect.Left - 3
                    TextRect.Right = PicX - 3
                Case Is = ppTop
                    PicX = (dw - PicW) / 2 + TextRect.Left - SizeCW
                    PicY = (DH - PicH - 3 - UserControl.TextHeight("I")) / 2 + TextRect.Top - SizeCH
                    TextRect.Top = PicY + PicW + 3
                    TextRect.Bottom = TextRect.Top + UserControl.TextHeight("I") * 1.2
                Case Is = ppBottom
                    TextRect.Top = (DH - PicH - 3 - UserControl.TextHeight("I")) / 2 + TextRect.Top - SizeCH
                    PicX = (dw - PicW) / 2 + TextRect.Left - SizeCW
                    TextRect.Bottom = TextRect.Top + UserControl.TextHeight("I") * 1.2
                    PicY = TextRect.Bottom + 3
                Case Is = ppCenter
                    PicX = (dw - PicW) / 2
                    If BTN_DOWN Then PicX = PicX + m_DisplaceText
                    bDrawText = False
            End Select

'            Debug.Print "State2 "; State

            If m_State = BTN_DISABLED Then
                'draw text and picture disabled
                DrawPictureDisabled m_Picture, PicX, PicY, PicW, PicH
                If m_TextColorDisabled <> m_TextColorDisabled2 Then
                    If bDrawText Then
                        UserControl.ForeColor = m_TextColorDisabled2
                        TextRect = ModifyRect(TextRect, 1, 1, 1, 1)

                        DrawText hdc, m_Text, TextRect, Align
                        TextRect = ModifyRect(TextRect, -1, -1, -1, -1)
                    End If
                End If

                UserControl.ForeColor = m_TextColorDisabled
                If bDrawText Then
                    DrawText hdc, m_Text, TextRect, Align
                End If
            Else
                'draw text and picture enabled
                UserControl.ForeColor = m_TextColorEnabled
                If bDrawText Then
                    DrawText hdc, m_Text, TextRect, Align
                End If
                DrawPicture hdc, m_Picture, PicX, PicY, PicW, PicH, m_PictureTColor
            End If
        End If

    Dim f As Long
    If m_DrawFocus > 0 Then
        If State = BTN_DOWN Or State = BTN_FOCUS Then
            f = CLng(m_DrawFocus)
            DrawFocusRect hdc, SetRect(f, f, dw - f, DH - f)
        End If
    End If

    UserControl.ForeColor = Pcolor
    If UserControl.AutoRedraw = True Then
        UserControl.Refresh
    End If
Exit Sub
UnknownError:

'most important line in this function
'i about 2 hours to find out
Set m_SkinPicture = Nothing
'removing this line form will not unload properly
End Sub

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=0,0,0,True
Public Property Get FillWithColor() As Boolean
    FillWithColor = m_FillWithColor
End Property

Public Property Let FillWithColor(ByVal New_FillWithColor As Boolean)
    m_FillWithColor = New_FillWithColor
    Refresh
    PropertyChanged "FillWithColor"
End Property


Public Sub Refresh()

    If m_State < 1 Or m_State > 5 Then m_State = 1
    If Enabled Then
        DrawButton m_State
    Else
        DrawButton BTN_DISABLED
    End If
End Sub
'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,hWnd
Public Property Get hwnd() As Long
    hwnd = UserControl.hwnd
End Property
 
Private Function PointInControl(x As Single, y As Single) As Boolean
  If x >= 0 And x <= UserControl.ScaleWidth And _
    y >= 0 And y <= UserControl.ScaleHeight Then
    PointInControl = True
  End If
End Function

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,Enabled
Public Property Get Enabled() As Boolean
    Enabled = UserControl.Enabled
End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)
    UserControl.Enabled() = New_Enabled

    If New_Enabled Then
        DrawButton BTN_NORMAL
    Else
        DrawButton BTN_DISABLED
    End If
    
    PropertyChanged "Enabled"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=10,0,0,0
Public Property Get TextColorEnabled() As Ole_Color
    TextColorEnabled = m_TextColorEnabled
End Property

Public Property Let TextColorEnabled(ByVal New_TextColorEnabled As Ole_Color)
    m_TextColorEnabled = New_TextColorEnabled
    Refresh
    PropertyChanged "TextColorEnabled"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=10,0,0,0
Public Property Get TextColorDisabled() As Ole_Color
    TextColorDisabled = m_TextColorDisabled
End Property

Public Property Let TextColorDisabled(ByVal New_TextColorDisabled As Ole_Color)
    m_TextColorDisabled = New_TextColorDisabled
    Refresh
    PropertyChanged "TextColorDisabled"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,Font
Public Property Get Font() As Font
    Set Font = UserControl.Font
End Property

Public Property Set Font(ByVal New_Font As Font)
    Set UserControl.Font = New_Font
    Refresh
    PropertyChanged "Font"
End Property



'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontUnderline
Public Property Get FontUnderline() As Boolean
    FontUnderline = UserControl.FontUnderline
End Property

Public Property Let FontUnderline(ByVal New_FontUnderline As Boolean)
    UserControl.FontUnderline() = New_FontUnderline
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontStrikethru
Public Property Get FontStrikethru() As Boolean
    FontStrikethru = UserControl.FontStrikethru
End Property

Public Property Let FontStrikethru(ByVal New_FontStrikethru As Boolean)
    UserControl.FontStrikethru() = New_FontStrikethru
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontSize
Public Property Get FontSize() As Single
    FontSize = UserControl.FontSize
End Property

Public Property Let FontSize(ByVal New_FontSize As Single)
    UserControl.FontSize() = New_FontSize
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontName
Public Property Get FontName() As String
    FontName = UserControl.FontName
End Property

Public Property Let FontName(ByVal New_FontName As String)
    UserControl.FontName() = New_FontName
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontItalic
Public Property Get FontItalic() As Boolean
    FontItalic = UserControl.FontItalic
End Property

Public Property Let FontItalic(ByVal New_FontItalic As Boolean)
    UserControl.FontItalic() = New_FontItalic
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,FontBold
Public Property Get FontBold() As Boolean
    FontBold = UserControl.FontBold
End Property

Public Property Let FontBold(ByVal New_FontBold As Boolean)
    UserControl.FontBold() = New_FontBold
    Refresh
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,MousePointer
Public Property Get MousePointer() As MousePointerConstants
    MousePointer = UserControl.MousePointer
End Property

Public Property Let MousePointer(ByVal New_MousePointer As MousePointerConstants)
    UserControl.MousePointer() = New_MousePointer
    PropertyChanged "MousePointer"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,MouseIcon
Public Property Get MouseIcon() As Picture
    Set MouseIcon = UserControl.MouseIcon
End Property

Public Property Set MouseIcon(ByVal New_MouseIcon As Picture)
    Set UserControl.MouseIcon = New_MouseIcon
    PropertyChanged "MouseIcon"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=0,0,0,False
Public Property Get DisableHover() As Boolean
    DisableHover = m_DisableHover
End Property

Public Property Let DisableHover(ByVal New_DisableHover As Boolean)
    m_DisableHover = New_DisableHover
    PropertyChanged "DisableHover"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get DisplaceText() As Integer
    DisplaceText = m_DisplaceText
End Property

Public Property Let DisplaceText(ByVal New_DisplaceText As Integer)
    m_DisplaceText = New_DisplaceText
    PropertyChanged "DisplaceText"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get DrawFocus() As Integer
    DrawFocus = m_DrawFocus
End Property

Public Property Let DrawFocus(ByVal New_DrawFocus As Integer)
    m_DrawFocus = New_DrawFocus
    PropertyChanged "DrawFocus"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=10,0,0,0
Public Property Get TextColorDisabled2() As Ole_Color
    TextColorDisabled2 = m_TextColorDisabled2
End Property

Public Property Let TextColorDisabled2(ByVal New_TextColorDisabled2 As Ole_Color)
    m_TextColorDisabled2 = New_TextColorDisabled2
    Refresh
    PropertyChanged "TextColorDisabled2"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=11,0,0,0
Public Property Get Picture() As StdPicture
    Set Picture = m_Picture
End Property

Public Property Set Picture(ByVal New_Picture As StdPicture)
    Set m_Picture = New_Picture
    Refresh
    PropertyChanged "Picture"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get PicturePos() As EnumPicturePos
    PicturePos = m_PicturePos
End Property

Public Property Let PicturePos(ByVal New_PicturePos As EnumPicturePos)
    m_PicturePos = New_PicturePos
    Refresh
    PropertyChanged "PicturePos"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=10,0,0,0
Public Property Get PictureTColor() As Ole_Color
    PictureTColor = m_PictureTColor
End Property

Public Property Let PictureTColor(ByVal New_PictureTColor As Ole_Color)
    m_PictureTColor = New_PictureTColor
    Refresh
    PropertyChanged "PictureTColor"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,0
Public Property Get TextAlign() As AlignmentConstants
    TextAlign = m_TextAlign
End Property

Public Property Let TextAlign(ByVal New_TextAlign As AlignmentConstants)
    m_TextAlign = New_TextAlign
    Refresh
    PropertyChanged "TextAlign"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=UserControl,UserControl,-1,BackColor
Public Property Get BackColor() As Ole_Color
    BackColor = UserControl.BackColor
End Property

Public Property Let BackColor(ByVal New_BackColor As Ole_Color)
    UserControl.BackColor() = New_BackColor
    Refresh
    PropertyChanged "BackColor"
End Property

  模块的实现(最后一步,最精彩的一步):

  其中,关于OCR匹配度计算的核心算法:

  For i = 1 To bi24BitInfo.bmiHeader.biWidth
  For j = 1 To bi24BitInfo.bmiHeader.biHeight

    //对每一个取样后的宽度和高度组成的一个像素点进行相似度比对,相等的话,就将相似度++
    If Pic2Bits(1, i, j) = PicBits(1, i, j) Then SameBits = SameBits + 1
  Next j
Next i
AllBits = bi24BitInfo.bmiHeader.biSizeImage

   //解算OCR的匹配度
OcrBits = SameBits / AllBits * 10000

  (1)初始化各种变量和函数:

  Public Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long
Public Declare Function ExtFloodFill Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long, ByVal wFillType As Long) As Long
Public Declare Function FloodFill Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
Public Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Public Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long

Public Const PS_SOLID = 0
Public Const PS_DASH = 1

Public Const FLOODFILLBORDER = 0
Public Const FLOODFILLSURFACE = 1

Public Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Public Declare Function SetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
Public Declare Function SetPixelV Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
Public Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Public Declare Function SetStretchBltMode Lib "gdi32" (ByVal hdc As Long, ByVal nStretchMode As Long) As Long

Public Const STRETCH_ANDSCANS = 1
Public Const STRETCH_DELETESCANS = 3
Public Const STRETCH_HALFTONE = 4
Public Const STRETCH_ORSCANS = 2

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (Destination As Any, ByVal Length As Long)

Public Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Public Declare Function FillRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long) As Long
Public Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long

Public Const WINDING = 2
Public Const ALTERNATE = 1

Public Type POINTAPI
        x As Long
        y As Long
End Type

Public Type OcrType
       SameBits As Long
       ModeText As String
End Type

Public Type SAFEARRAY2
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
    CE0 As Long
    LB0 As Long
    CE1 As Long
    LB1 As Long
End Type

Public Type BITMAPINFOHEADER '40 bytes
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As Long
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
End Type

Public Type RGBQUAD
        rgbBlue As Byte
        rgbGreen As Byte
        rgbRed As Byte
        rgbReserved As Byte
End Type

Public Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type

Public Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        bmiColors As RGBQUAD
End Type

Public Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Public Declare Function TransparentBlt Lib "msimg32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean
Public Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Public Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Public Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Public Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Public Declare Function GetTickCount Lib "kernel32" () As Long
Public Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pBitmapInfo As BITMAPINFO, ByVal un As Long, ByVal lplpVoid As Long, ByVal handle As Long, ByVal dw As Long) As Long
Public Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Public Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long

Public Const BI_RGB = 0&
Public Const DIB_RGB_COLORS = 0
Public Const IMAGE_BITMAP As Long = 0
Public Const LR_LOADFROMFILE As Long = &H10
Public Const LR_CREATEDIBSECTION As Long = &H2000
Public Const LR_DEFAULTCOLOR As Long = &H0
Public Const LR_COLOR As Long = &H2
Public Const SRCAND = &H8800C6
Public Const SRCCOPY = &HCC0020
Public Const SRCERASE = &H440328
Public Const SRCPAINT = &HEE0086
Public Const SRCINVERT = &H660046

Public Declare Function GetObjectA Lib "gdi32" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Public Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Public Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long

 //该函数设置边界值,color的边界值不能超过255,由于一个(R,G,B)的每一个单元只能在0--255之间
Public Function ksCheckBounds(ByVal Color As Long) As Byte
If Color > 255 Then
    ksCheckBounds = 255
ElseIf Color > -1 Then
    ksCheckBounds = Color
End If
End Function

 //分别得到Red,Blue,Green的值,利用位运算
Public Function GetRedValue(Color As Long) As Integer
GetRedValue = Color And &HFF
End Function

Public Function GetGreenValue(Color As Long) As Integer
GetGreenValue = (Color And 65280) \ 256
End Function

Public Function GetBlueValue(Color As Long) As Integer
GetBlueValue = (Color And &HFF0000) \ 65536
End Function

 

//这个应该是一个排序的算法吧,研究中……
Function Kspxd(R() As OcrType, t As Long, w As Long)
Dim i As Long, j As Long, k As Long, x As Long, XType As OcrType
i = t
j = w
x = R(i).SameBits
XType = R(i)
Do
  Do While (R(j).SameBits >= x) And (j > i)
    j = j - 1
'    DoEvents
  Loop
  If i < j Then
    R(i) = R(j)
    i = i + 1
  End If
  Do While (R(i).SameBits <= x) And (j > i)
    i = i + 1
'    DoEvents
  Loop
  If i < j Then
    R(j) = R(i)
    j = j - 1
  End If
'  DoEvents
Loop While i < j
R(i) = XType
If j - 1 > t Then Kspxd R, t, j - 1
If j + 1 < w Then Kspxd R, j + 1, w
End Function

 //这是一个修正函数,如果num是一个double型浮点数的话,将其修正为整型的
Public Function LargeFix(num As Double)
LargeFix = Int(num) + 1
End Function

  (2)最后一步,实现具体的OCR算法

  为了增大OCR匹配度的准确率,增加两个小插件(过程),(1)考虑到颜色的不同模糊识别,加入二值化处理(2)去除文字外的一些多余部分

  Public Function OcrBits(Pic1 As PictureBox, Pic2 As PictureBox) As Long '实际进行OCR识别的模块
Dim i As Long, j As Long
Dim hOldMap As Long
Dim PicBits() As Byte
Dim iBitmap As Long, iDC As Long
Dim bi24BitInfo As BITMAPINFO
Dim Pic2Bits() As Byte
Dim i2Bitmap As Long, i2DC As Long
Dim bi24Bit2Info As BITMAPINFO
Dim AllBits As Long, SameBits As Long
With bi24BitInfo.bmiHeader
    .biBitCount = 32
    .biCompression = BI_RGB
    .biPlanes = 1
    .biSize = Len(bi24BitInfo.bmiHeader)
    .biWidth = Pic1.ScaleWidth
    .biHeight = Pic1.ScaleHeight
    .biSizeImage = .biWidth * 4 * .biHeight
End With
iDC = CreateCompatibleDC(0)
iBitmap = CreateDIBSection(iDC, bi24BitInfo, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, ByVal 0&)
If iBitmap Then
  hOldMap = SelectObject(iDC, iBitmap)
Else
  DeleteObject iDC
  Exit Function
End If
BitBlt iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, Pic1.hdc, 0, 0, vbSrcCopy
ReDim PicBits(1 To 4, 1 To bi24BitInfo.bmiHeader.biWidth, 1 To bi24BitInfo.bmiHeader.biHeight) As Byte
GetBitmapBits iBitmap, bi24BitInfo.bmiHeader.biSizeImage, PicBits(1, 1, 1)

With bi24Bit2Info.bmiHeader
    .biBitCount = 32
    .biCompression = BI_RGB
    .biPlanes = 1
    .biSize = Len(bi24BitInfo.bmiHeader)
    .biWidth = Pic2.ScaleWidth
    .biHeight = Pic2.ScaleHeight
    .biSizeImage = .biWidth * 4 * .biHeight
End With
i2DC = CreateCompatibleDC(0)
i2Bitmap = CreateDIBSection(i2DC, bi24Bit2Info, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, ByVal 0&)
If i2Bitmap Then
  hOldMap = SelectObject(i2DC, i2Bitmap)
Else
  DeleteObject i2DC
  Exit Function
End If
BitBlt i2DC, 0, 0, bi24Bit2Info.bmiHeader.biWidth, bi24Bit2Info.bmiHeader.biHeight, Pic2.hdc, 0, 0, vbSrcCopy
ReDim Pic2Bits(1 To 4, 1 To bi24Bit2Info.bmiHeader.biWidth, 1 To bi24Bit2Info.bmiHeader.biHeight) As Byte
GetBitmapBits i2Bitmap, bi24Bit2Info.bmiHeader.biSizeImage, Pic2Bits(1, 1, 1)
AreaHeight = LargeFix(Pic2.ScaleHeight / 4)
AreaWidth = LargeFix(Pic2.ScaleWidth / 4)
For i = 1 To bi24BitInfo.bmiHeader.biWidth
  For j = 1 To bi24BitInfo.bmiHeader.biHeight

    //对每一个取样后的宽度和高度组成的一个像素点进行相似度比对,相等的话,就将相似度++
    If Pic2Bits(1, i, j) = PicBits(1, i, j) Then SameBits = SameBits + 1
  Next j
Next i
AllBits = bi24BitInfo.bmiHeader.biSizeImage

   //解算OCR的匹配度
OcrBits = SameBits / AllBits * 10000
If hOldMap Then DeleteObject SelectObject(iDC, hOldMap)
DeleteObject iDC
If hOldMap Then DeleteObject SelectObject(i2DC, hOldMap)
DeleteObject i2DC
End Function

Public Function BlackBits(Pic As PictureBox) '将图象简单二值化,主要是因为实时生成的文字不是纯黑色
Dim i As Long
Dim hOldMap As Long
Dim PicBits() As Byte
Dim iBitmap As Long, iDC As Long
Dim bi24BitInfo As BITMAPINFO
With bi24BitInfo.bmiHeader
    .biBitCount = 32
    .biCompression = BI_RGB
    .biPlanes = 1
    .biSize = Len(bi24BitInfo.bmiHeader)
    .biWidth = Pic.ScaleWidth
    .biHeight = Pic.ScaleHeight
    .biSizeImage = .biWidth * 4 * .biHeight
End With
iDC = CreateCompatibleDC(0)
iBitmap = CreateDIBSection(iDC, bi24BitInfo, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, ByVal 0&)
If iBitmap Then
  hOldMap = SelectObject(iDC, iBitmap)
Else
  DeleteObject iDC
  Exit Function
End If
BitBlt iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, Pic.hdc, 0, 0, vbSrcCopy
ReDim PicBits(0 To bi24BitInfo.bmiHeader.biSizeImage) As Byte
GetBitmapBits iBitmap, bi24BitInfo.bmiHeader.biSizeImage, PicBits(0)

  //二值化核心代码
For i = 0 To bi24BitInfo.bmiHeader.biSizeImage
  If PicBits(i) <> 255 Then PicBits(i) = 0
Next i
SetBitmapBits iBitmap, bi24BitInfo.bmiHeader.biSizeImage, PicBits(0)
BitBlt Pic.hdc, 0, 0, bi24BitInfo.bmiHeader.biWidth, bi24BitInfo.bmiHeader.biHeight, iDC, 0, 0, vbSrcCopy
Pic.Refresh
If hOldMap Then DeleteObject SelectObject(iDC, hOldMap)
DeleteObject iDC
BlackBits = True
End Function

Function CutLetters(Pic As PictureBox) As RECT '切掉文字旁边不需要的部分,以提高识别率
Dim i As Long, j As Long
CutLetters.Left = -1
CutLetters.Right = -1
CutLetters.Top = -1
CutLetters.Bottom = -1
For i = 0 To Pic.ScaleWidth
  For j = 0 To Pic.ScaleHeight
    If GetPixel(Pic.hdc, i, j) = &H0& Then CutLetters.Left = i
  Next j
  If CutLetters.Left <> -1 Then Exit For
Next i
For i = Pic.ScaleWidth To 0 Step -1
  For j = Pic.ScaleHeight To 0 Step -1
    If GetPixel(Pic.hdc, i, j) = &H0& Then CutLetters.Right = i + 1
  Next j
  If CutLetters.Right <> -1 Then Exit For
Next i
For j = 0 To Pic.ScaleHeight
  For i = 0 To Pic.ScaleWidth
    If GetPixel(Pic.hdc, i, j) = &H0& Then CutLetters.Top = j
  Next i
  If CutLetters.Top <> -1 Then Exit For
Next j
For j = Pic.ScaleHeight To 0 Step -1
  For i = Pic.ScaleWidth To 0 Step -1
    If GetPixel(Pic.hdc, i, j) = &H0& Then CutLetters.Bottom = j + 1
  Next i
  If CutLetters.Bottom <> -1 Then Exit For
Next j
End Function
 

你可能感兴趣的:(round)