.NETスクリプトで除外領域を指定してビットマップオブジェクトの比較を行う
.NET スクリプトでは、.NET Frameworkの高度な機能が簡単に使用できます。
このサンプルコードは、ビットマップオブジェクト同士を高速に比較し、差異を強調した画像ファイルとして保存することができます。
また、画像比較の際に除外領域を指定することも出来ます。
- ※Silk Test 14.0からイメージ検証機能が追加されました。
共有モジュールとしてコーディングを行う
- 共有モジュールとしてBmpDiffVBクラスを作成
- ファイルメニューから「新規作成 → .NETスクリプト」、資産名「BmpDiff」として空の資産を作成します。
- 次のプログラムをそのまま共有モジュールの内容に貼り付けて保存します。
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Public Class BmpDiffVB
Private bmpBody1 As BitmapData
Private bmpBody2 As BitmapData
Private bmpBodyR As BitmapData
Private bmpData1 As Bitmap
Private bmpData2 As Bitmap
Private bmpDataR As Bitmap
Private fmtData1 As PixelFormat
Private fmtData2 As PixelFormat
Private isSizeDiffer As Boolean
Private lstExcluded As List(Of Rectangle)
Public ReadOnly Property LastResult() As Bitmap
Get
Dim bitmap As Bitmap = Me.bmpDataR
Return bitmap
End Get
End Property
Public Sub New(ByVal strFilename1 As String, ByVal strFilename2 As String)
MyBase.New()
Me.fmtData1 = PixelFormat.Format24bppRgb
Me.fmtData2 = PixelFormat.Format24bppRgb
Me.lstExcluded = New List(Of Rectangle)()
Me.isSizeDiffer = False
Me.bmpData1 = New Bitmap(strFilename1)
Me.bmpData2 = New Bitmap(strFilename2)
Me.bmpDataR = Me.bmpData1.Clone(New Rectangle(0, 0, Me.bmpData1.Width, Me.bmpData1.Height), Me.bmpData1.PixelFormat)
Me.bmpBody1 = Nothing
Me.bmpBody2 = Nothing
Me.isSizeDiffer = Me.chkSize()
End Sub
Public Sub New(ByVal a_Bmp1 As Bitmap, ByVal a_Bmp2 As Bitmap)
MyBase.New()
Me.fmtData1 = PixelFormat.Format24bppRgb
Me.fmtData2 = PixelFormat.Format24bppRgb
Me.lstExcluded = New List(Of Rectangle)()
Me.isSizeDiffer = False
Me.bmpData1 = a_Bmp1
Me.bmpData2 = a_Bmp2
Me.bmpDataR = Me.bmpData1.Clone(New Rectangle(0, 0, Me.bmpData1.Width, Me.bmpData1.Height), Me.bmpData1.PixelFormat)
Me.bmpBody1 = Nothing
Me.bmpBody2 = Nothing
Me.isSizeDiffer = Me.chkSize()
End Sub
Public Sub AddExcluded(ByVal r As Rectangle)
Me.lstExcluded.Add(r)
End Sub
Public Function chkSize() As Boolean
Dim flag As Boolean
Dim height As Boolean
If (Me.bmpData1.Width <> Me.bmpData2.Width) Then
height = False
Else
height = Me.bmpData1.Height = Me.bmpData2.Height
End If
If (height) Then
flag = False
Else
flag = True
End If
Return flag
End Function
Public Function GetDepth(ByVal pic As PixelFormat) As Integer
Select Case pic
Case PixelFormat.Format32bppPArgb
Return 4
Case PixelFormat.Format32bppArgb
Return 4
Case PixelFormat.Format24bppRgb
Return 3
Case PixelFormat.Format32bppRgb
Return 4
End Select
Throw New InvalidOperationException("Unsupported pixel format")
End Function
Public Function Compare() As Boolean
Me.setTurbo()
If Me.isSizeDiffer Then
Return False
End If
If (Me.fmtData1 <> Me.fmtData2) Then
Return False
End If
Dim bResult As Boolean = True
If (Not Me.bmpBody1 Is Nothing) Then
Dim depth As Integer = Me.GetDepth(Me.fmtData1)
Dim adr1 As IntPtr = Me.bmpBody1.Scan0
Dim adr2 As IntPtr = Me.bmpBody2.Scan0
Dim adrR As IntPtr = Me.bmpBodyR.Scan0
Dim y As Integer
For y = 0 To Me.bmpData1.Height - 1
Dim x As Integer
For x = 0 To Me.bmpBody1.Width - 1
Dim pos As Integer = ((x * depth) + (Me.bmpBody1.Stride * y))
Dim isDifferent As Boolean = False
For i As Integer = 0 To depth - 1
Dim b1 As Byte = Marshal.ReadByte(adr1, (pos + i))
Dim b2 As Byte = Marshal.ReadByte(adr2, (pos + i))
If (b1 <> b2) Then
isDifferent = True
End If
i += 1
Next
If isDifferent Then
For i As Integer = 0 To depth - 1
Marshal.WriteByte(adrR, (pos + i), &HFF)
i += 1
Next i
bResult = False
Else
For i As Integer = 0 To depth - 1
Dim bR As Byte = CByte((Marshal.ReadByte(adrR, (pos + i)) >> 2))
Marshal.WriteByte(adrR, (pos + i), bR)
Next i
End If
Next x
Next y
End If
Me.bmpData1.UnlockBits(Me.bmpBody1)
Me.bmpData2.UnlockBits(Me.bmpBody2)
Me.bmpDataR.UnlockBits(Me.bmpBodyR)
Return bResult
End Function
Public Function Compare(ByVal strResultFile As String) As Boolean
Dim bRet As Boolean = Me.Compare()
If (strResultFile <> Nothing) Then
Me.bmpDataR.Save(strResultFile)
End If
Dim flag As Boolean = bRet
Return flag
End Function
Public Function Compare(ByRef resultBMP As Bitmap) As Boolean
Dim bRet As Boolean = Me.Compare()
resultBMP = DirectCast(Me.bmpDataR.Clone(), Bitmap)
Dim flag As Boolean = bRet
Return flag
End Function
Private Sub setTurbo()
Dim right As Boolean = False
If (Me.isSizeDiffer) Then
Return
End If
Me.bmpBody1 = Me.bmpData1.LockBits(New Rectangle(0, 0, Me.bmpData1.Width, Me.bmpData1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Me.bmpBody2 = Me.bmpData2.LockBits(New Rectangle(0, 0, Me.bmpData2.Width, Me.bmpData2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Me.bmpBodyR = Me.bmpDataR.LockBits(New Rectangle(0, 0, Me.bmpDataR.Width, Me.bmpDataR.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Dim adr1 As IntPtr = Me.bmpBody1.Scan0
Dim adr2 As IntPtr = Me.bmpBody2.Scan0
Dim depth As Integer = Me.GetDepth(Me.fmtData1)
For Each r As Rectangle In lstExcluded
For y As Integer = r.Top To r.Bottom
For x As Integer = r.Left To r.Right
Dim pos As Integer = x * depth + bmpBody1.Stride * y
For i As Integer = 0 To depth - 1
System.Runtime.InteropServices.Marshal.WriteByte(adr1, pos + i, 0)
System.Runtime.InteropServices.Marshal.WriteByte(adr2, pos + i, 0)
Next
Next
Next
Next
End Sub
End Class
他の.NETスクリプトからの呼び出し例
上記で作成した.NETスクリプトは、共有モジュールとして利用できます。プロパティの[参照]→[.NETスクリプト]で「.NETスクリプト参照の追加」を選択して、common.BmpDiffを追加してください。
たとえば、次のプログラムは、Windows7の「砂漠.jpg」と、「クラゲ.jpg」を比較し、比較結果を「result.bmp」という名前で保存しています。
また、除外領域として左上から100x100ドットの矩形部分を定義します。
今回紹介したクラスは、ビットマップファイルを比較することはできません。そのため、Bitmapオブジェクトを作成してから保存している点に注意してください。
Public Module Main
Dim _desktop As Desktop = Agent.Desktop
Public Sub Main()
Dim bmp1 As New Bitmap("C:\Users\Public\Pictures\Sample Pictures\Desert.jpg")
Dim bmp2 As New Bitmap("C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg")
Dim diff As BmpDiffVB = New BmpDiffVB(bmp1,bmp2)
Dim bret As Boolean
diff.AddExcluded(New Rectangle(0,0,100,100) )
bret = diff.Compare("C:\Users\Public\Pictures\Sample Pictures\result.bmp")
Workbench.Verify(bret)
End Sub
End Module
免責事項
ここで紹介したスクリプトは説明のためのサンプルであり、製品の一部ではございません。スクリプトが実際に動作するか、御社業務に適合するかなどに関しまして、一切の保証はございません。
スクリプト、説明、その他すべてについて、無謬性は保障されません。
ここで紹介するスクリプトの一部、もしくは全部について、弊社に断りなく、御社スクリプトの内部に組み込み、そのままご利用頂いても構いません。
本スクリプトの一部もしくは全部を二次的著作物に対して引用する場合、著作権法の精神に基づき、適切な扱いを行ってください。