vbAccelerator - Contents of code file: cCompositing.cls

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "cCompositing"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

Private Type SAFEARRAYBOUND
    cElements As Long
    lLbound As Long
End Type
Private Type SAFEARRAY2D
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
    Bounds(0 To 1) As SAFEARRAYBOUND
End Type
Private Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Ptr()
 As Any) As Long



Public Enum CompositingOperations
   
   ' // Porter-Duff compositing operations
   
   ' // <summary>
   ' // Both the color and the alpha of the destination are cleared. Neither
    the source nor the destination are used as input.
   ' //</summary>
   compositeClear = 0
   
   ' // <summary>
   ' // The source is copied to the destination. The destination is not used as
    input.
   ' //</summary>
   compositeSrc = 1
   
   ' // <summary>
   ' // The destination is left untouched.
   ' // </summary>
   compositeDst = 2
   
   ' // <summary>
   ' // The source is composited over the destination.
   ' // </summary>
   compositeSrcOver = 3
   
   ' // <summary>
   ' // The destination is composited over the source and the result replaces
    the destination.
   ' // </summary>
   compositeDstOver = 4
   
   ' // <summary>
   ' // The part of the source lying inside of the destination replaces the
    destination.
   ' // </summary>
   compositeSrcIn = 5
   
   ' // <summary>
   ' // The part of the destination lying inside of the source replaces the
    destination.
   ' // </summary>
   compositeDstIn = 6
   
   ' // <summary>
   ' // The part of the source lying outside of the destination replaces the
    destination.
   ' // </summary>
   compositeSrcOut = 7
   
   ' // <summary>
   ' // The part of the destination lying outside of the source replaces the
    destination.
   ' // </summary>
   compositeDstOut = 8
   
   ' // <summary>
   ' // The part of the source lying inside of the destination is composited
    onto the destination.
   ' // </summary>
   compositeSrcAtop = 9
   
   ' // <summary>
   ' // The part of the destination lying inside of the source is composited
    over the source and replaces the destination.
   ' // </summary>
   compositeDstAtop = 10
   
   ' // <summary>
   ' // The part of the source that lies outside of the destination is combined
    with the part of the destination that lies outside of the source.
   ' // </summary>
   compositeXor = 11
   
   ' // Extended compositing operations
   
   ' // <summary>
   ' // The source is added to the destination and replaces the destination.
    This operator is useful for animating a dissolve between two images.
   ' // </summary>
   compositePlus = 12
   
   ' // <summary>
   ' // The source is multiplied by the destination and replaces the
    destination. The resultant color is always at least as dark as either of
    the two constituent colors. Multiplying any color with black produces
    black. Multiplying any color with white leaves the original color unchanged.
   ' // </summary>
   compositeMultiply = 13
   
   ' // <summary>
   ' // The source and destination are complemented and then multiplied and
    then replace the destination. The resultant color is always at least as
    light as either of the two constituent colors. Screening any color with
    white produces white. Screening any color with black leaves the original
    color unchanged.
   ' // </summary>
   compositeScreen = 14
    
   ' // <summary>
   ' // Multiplies or screens the colors, dependent on the destination color.
    Source colors overlay the destination whilst preserving its highlights and
    shadows. The destination color is not replaced, but is mixed with the
    source color to reflect the lightness or darkness of the destination.
   ' // </summary>
   compositeOverlay = 15
   
   ' // <summary>
   ' // Selects the darker of the destination and source colors. The
    destination is replaced with the source when the source is darker,
    otherwise it is left unchanged.
   ' // </summary>
   compositeDarken = 16
   
   ' // <summary>
   ' // Selects the lighter of the destination and source colors. The
    destination is replaced with the source when the source is lighter,
    otherwise it is left unchanged.
   ' // </summary>
   compositeLighten = 17
   
   ' // <summary>
   ' // Brightens the destination color to reflect the source color. Painting
    with black produces no change.
   ' // </summary>
   compositeColorDodge = 18
   
   ' // <summary>
   ' // Darkens the destination color to reflect the source color. Painting
    with white produces no change.
   ' // </summary>
   compositeColorBurn = 19
   
   ' // <summary>
   ' // Multiplies or screens the colors, dependent on the source color value.
    If the source color is lighter than 0.5, the destination is lightened as if
    it were screened. If the source color is darker than 0.5, the destination
    is darkened, as if it were multiplied. The degree of lightening or
    darkening is proportional to the difference between the source color and
    0.5. If it is equal to 0.5 the destination is unchanged. Painting with pure
    black or white produces black or white.
   ' // </summary>
   compositeHardLight = 20
   
   ' // <summary>
   ' // Darkens or lightens the colors, dependent on the source color value. If
    the source color is lighter than 0.5, the destination is lightened. If the
    source color is darker than 0.5, the destination is darkened, as if it were
    burned in. The degree of darkening or lightening is proportional to the
    difference between the source color and 0.5. If it is equal to 0.5, the
    destination is unchanged. Painting with pure black or white produces a
    distinctly darker or lighter area, but does not result in pure black or
    white.
   ' // </summary>
   compositeSoftLight = 21
   
   ' // <summary>
   ' // Subtracts the darker of the two constituent colors from the lighter.
    Painting with white inverts the destination color. Painting with black
    produces no change.
   ' // </summary>
   compositeDifference = 22
   
   ' // <summary>
   ' // Produces an effect similar to that of 'difference', but appears as
    lower contrast. Painting with white inverts the destination color. Painting
    with black produces no change.
   ' // </summary>
   compositeExclusion = 23
   
End Enum

Private m_cDibDst As cAlphaDibSection
Private m_cDibSrc As cAlphaDibSection
Private m_srcX As Long
Private m_srcY As Long
Private m_srcWidth As Long
Private m_srcHeight As Long
Private m_dstX As Long
Private m_dstY As Long
Private m_dstWidth As Long
Private m_dstHeight As Long
Private m_resWidth As Long
Private m_resHeight As Long

Private m_eOperation As CompositingOperations

Public Property Get Src() As cAlphaDibSection
   Set Src = m_cDibSrc
End Property
Public Property Let Src(value As cAlphaDibSection)
   Set m_cDibSrc = value
End Property
Public Property Set Src(value As cAlphaDibSection)
   Set m_cDibSrc = value
End Property

Public Property Get srcX() As Long
   srcX = m_srcX
End Property
Public Property Let srcX(ByVal value As Long)
   m_srcX = value
End Property
Public Property Get srcY() As Long
   srcY = m_srcY
End Property
Public Property Let srcY(ByVal value As Long)
   m_srcY = value
End Property
Public Property Get srcWidth() As Long
   srcWidth = m_srcWidth
End Property
Public Property Let srcWidth(ByVal value As Long)
   m_srcWidth = value
End Property
Public Property Get srcHeight() As Long
   srcHeight = m_srcHeight
End Property
Public Property Let srcHeight(ByVal value As Long)
   m_srcHeight = value
End Property

Public Property Get Dst() As cAlphaDibSection
   Set Dst = m_cDibDst
End Property
Public Property Let Dst(value As cAlphaDibSection)
   Set m_cDibDst = value
End Property
Public Property Set Dst(value As cAlphaDibSection)
   Set m_cDibDst = value
End Property

Public Property Get operation() As CompositingOperations
   operation = m_eOperation
End Property
Public Property Let operation(ByVal eOperation As CompositingOperations)
   m_eOperation = eOperation
End Property

Public Sub Composite()
   
   Select Case m_eOperation
   Case compositeClear
      PerformCompositeClear
   Case compositeSrc
      PerformCompositeSrc
   Case compositeDst
      PerformCompositeDst
   Case compositeSrcOver
      PerformCompositeSrcOver
   Case compositeDstOver
      PerformCompositeDstOver
   Case compositeSrcIn
      PerformCompositeSrcIn
   Case compositeDstIn
      PerformCompositeDstIn
   Case compositeSrcOut
      PerformCompositeSrcOut
   Case compositeDstOut
      PerformCompositeDstOut
   Case compositeSrcAtop
      PerformCompositeSrcAtop
   Case compositeDstAtop
      PerformCompositeDstAtop
   Case compositeXor
      PerformCompositeXor
   Case compositePlus
      PerformCompositePlus
   Case compositeMultiply
      PerformCompositeMultiply
   Case compositeScreen
      PerformCompositeScreen
   Case compositeOverlay
      PerformCompositeOverlay
   Case compositeDarken
      PerformCompositeDarken
   Case compositeLighten
      PerformCompositeLighten
   Case compositeColorDodge
      PerformCompositeColorDodge
   Case compositeColorBurn
      PerformCompositeColorBurn
   Case compositeHardLight
      PerformCompositeHardLight
   Case compositeSoftLight
      PerformCompositeSoftLight
   Case compositeDifference
      PerformCompositeDifference
   Case compositeExclusion
      PerformCompositeExclusion
   End Select
   
End Sub

Public Sub PerformCompositeClear()
' Both the color and the alpha of the destination are cleared. Neither the
 source nor the destination are used as input.
'  Dc ' = 0
'  Da ' = 0
   
Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long
   
   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then
   
      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            bDibDst(x, y) = 0
            bDibDst(x + 1, y) = 0
            bDibDst(x + 2, y) = 0
            bDibDst(x + 3, y) = 0
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4
   
   End If
   
End Sub
Public Sub PerformCompositeSrc()
'The source is copied to the destination. The destination is not used as input.
'
'  Dc ' = Sc.Da + Sc.(1 - Da)
'      = Sc
'  Da ' = Sa.Da + Sa.(1 - Da)
'      = Sa

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            '  Dc ' = Sc.Da + Sc.(1 - Da)
            '      = Sc
            bDibDst(x, y) = bDib(x, y)
            bDibDst(x + 1, y) = bDib(x + 1, y)
            bDibDst(x + 2, y) = bDib(x + 2, y)
            
            '  Da ' = Sa.Da + Sa.(1 - Da)
            '      = Sa
            bDibDst(x + 3, y) = bDib(x + 3, y)
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDst()
'The destination is left untouched.
'
'  Dc ' = Dc.Sa + Dc.(1 - Sa)
'      = Dc
'  Da ' = Da.Sa + Da.(1 - Sa)
'      = Da

   ' This compositing operation results in the destination
   ' being unchanged.  It's rather easy to do, but also
   ' hard to describe as a 'compositing' operation either...
   
   ' For a more tricky challenge, you may instead wish to
   ' consider how to produce an O(log N) algorithm for
   ' factoring a large composite into its two constituent
   ' primes. If you find one then please send it to me for,
   ' erm, independent verification.
   
End Sub
Public Sub PerformCompositeSrcOver()
'The source is composited over the destination.
'
'  Dc ' = Sc.Da + Sc.(1 - Da) + Dc.(1 - Sa)
'      = Sc + Dc.(1 - Sa)
'  Da ' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa)
'      = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1

      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            '  Dc ' = Sc.Da + Sc.(1 - Da) + Dc.(1 - Sa)
            '      = Sc + Dc.(1 - Sa)
            bDibDst(x, y) = bDib(x, y) + (bDibDst(x, y) * (255& - bDib(x + 3,
             y))) / 255&
            bDibDst(x + 1, y) = bDib(x + 1, y) + (bDibDst(x + 1, y) * (255& -
             bDib(x + 3, y))) / 255&
            bDibDst(x + 2, y) = bDib(x + 2, y) + (bDibDst(x + 2, y) * (255& -
             bDib(x + 3, y))) / 255&
            
            '  Da ' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa)
            '      = Sa + Da - Sa.Da
            bDibDst(x + 3, y) = bDib(x + 3, y) * 1& + bDibDst(x + 3, y) -
             (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDstOver()
'The destination is composited over the source and the result replaces the
 destination.
'
'  Dc ' = Dc.Sa + Sc.(1 - Da) + Dc.(1 - Sa)
'      = Dc + Sc.(1 - Da)
'  Da ' = Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
'      = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Dc.Sa + Sc.(1 - Da) + Dc.(1 - Sa)
            '      = Dc + Sc.(1 - Da)
            lR = bDibDst(x + 2, y) + (bDib(x + 2, y) * (255& - bDibDst(x + 3,
             y))) / 255&
            bDibDst(x + 2, y) = lR
            lG = bDibDst(x + 1, y) + (bDib(x + 1, y) * (255& - bDibDst(x + 3,
             y))) / 255&
            bDibDst(x + 1, y) = lG
            lB = bDibDst(x, y) + (bDib(x, y) * (255& - bDibDst(x + 3, y))) /
             255&
            bDibDst(x, y) = lB
            
            '  Da ' = Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
            '      = Sa + Da - Sa.Da
            lA = 1& * bDib(x + 3, y) + bDibDst(x + 3, y)
            lA = lA - ((bDibDst(x + 3, y) * 1& * bDib(x + 3, y)) / 255&)
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeSrcIn()
'The part of the source lying inside of the destination replaces the
 destination.
'
'  Dc ' = Sc.Da
'  Da ' = Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Sc.Da
            lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Sa.Da
            lA = (bDibDst(x + 3, y) * 1& * bDib(x + 3, y)) / 255&
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDstIn()
'The part of the destination lying inside of the source replaces the
 destination.
'
'  Dc ' = Dc.Sa
'  Da ' = Da.Sa

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Dc.Sa
            lR = (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Sa.Da
            lA = (bDibDst(x + 3, y) * 1& * bDib(x + 3, y)) / 255&
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub

Public Sub PerformCompositeSrcOut()
'The part of the source lying outside of the destination replaces the
 destination.
'
'  Dc ' = Sc.(1 - Da)
'  Da ' = Sa.(1 - Da)

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Sc.(1 - Da)
            lR = bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Sa.(1 - Da)
            lA = bDib(x + 3, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDstOut()
'The part of the destination lying outside of the source replaces the
 destination.
'
' Dc ' = Dc.(1 - Sa)
' Da ' = Da.(1 - Sa)

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1

      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            ' Dc ' = Dc.(1 - Sa)
            lR = (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            bDibDst(x + 2, y) = lR
            lG = (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            bDibDst(x + 1, y) = lG
            lB = (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            bDibDst(x, y) = lB
            
            ' Da ' = Da.(1 - Sa)
            lA = (bDibDst(x + 3, y) * (255& - bDib(x + 3, y))) / 255&
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeSrcAtop()
'The part of the source lying inside of the destination is composited onto the
 destination.
'
'  Dc ' = Sc.Da + Dc(1 - Sa)
'  Da ' = Sa.Da + Da(1 - Sa)
'      = Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Sc.Da + Dc(1 - Sa)
            lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255& + _
               bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255& + _
               bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255& + _
               bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Sa.Da + Da(1 - Sa)
            '      = Da
            ' no change
            
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDstAtop()
'The part of the destination lying inside of the source is composited over the
 source and replaces the destination.
'
'  Dc ' = Dc.Sa + Sc.(1 - Da)
'  Da ' = Da.Sa + Sa.(1 - Da)
'      = Sa

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Dc.Sa + Sc.(1 - Da)
            lR = (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255& + _
               bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255& + _
               bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255& + _
               bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Da.Sa + Sa.(1 - Da)
            '      = Sa
            bDibDst(x + 3, y) = bDib(x + 3, y)
            
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeXor()
'The part of the source that lies outside of the destination is combined with
 the part of the destination that lies outside of the source.
'
'  Dc ' = Sc.(1 - Da) + Dc.(1 - Sa)
'  Da ' = Sa.(1 - Da) + Da.(1 - Sa)
'      = Sa + Da - 2.Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  Dc ' = Sc.(1 - Da) + Dc.(1 - Sa)
            lR = bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255& + _
               bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x + 2, y) = lR
            lG = bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255& + _
               bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x + 1, y) = lG
            lB = bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255& + _
               bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            bDibDst(x, y) = lB
            
            '  Da ' = Sa.(1 - Da) + Da.(1 - Sa)
            '      = Sa + Da - 2.Sa.Da
            bDibDst(x + 3, y) = (bDib(x + 3, y) * 1& + bDibDst(x + 3, y)) - _
               ((bDib(x + 3, y) * 2& * bDibDst(x + 3, y))) / 255&
            
         Next y
      Next x
            
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositePlus()
'The source is added to the destination and replaces the destination. This
 operator is useful for animating a dissolve between two images.
' NB:Clamp results
'  Dc ' = Sc.Da + Dc.Sa + Sc.(1 - Da) + Dc.(1 - Sa)
'      = Sc + Dc
'  Da ' = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
'      = Sa + Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
         
            '  Dc ' = Sc.Da + Dc.Sa + Sc.(1 - Da) + Dc.(1 - Sa)
            '      = Sc + Dc
            lB = bDib(x, y)
            lB = lB + bDibDst(x, y)
            If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB
            lG = bDib(x + 1, y)
            lG = lG + bDibDst(x + 1, y)
            If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG
            lR = bDib(x + 2, y)
            lR = lR + bDibDst(x + 2, y)
            If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
      
            '  Da ' = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
            '      = Sa + Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
            
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeMultiply()
'The source is multiplied by the destination and replaces the destination. The
 resultant color is always at least as dark as either of the two constituent
 colors. Multiplying any color with black produces black. Multiplying any color
 with white leaves the original color unchanged.
'  Dc ' = Sc.Dc + Sc.(1 - Da) + Dc.(1 - Sa)
'  Da ' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa)
'       = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
                              
            '  Dc ' = Sc.Dc + Sc.(1 - Da) + Dc.(1 - Sa)
            lB = bDib(x, y)
            lB = (lB * bDibDst(x, y)) / 255&
            lB = lB + bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
            lB = lB + bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            'If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB
            
            lG = bDib(x + 1, y)
            lG = (lG * bDibDst(x + 1, y)) / 255&
            lG = lG + bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
            lG = lG + bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            'If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG
            
            lR = bDib(x + 2, y)
            lR = (lR * bDibDst(x + 2, y)) / 255&
            lR = lR + bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
            lR = lR + bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            'If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
            
            
            '  Da ' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa)
            '       = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
            'If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
         Next y
      Next x
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeScreen()
'The source and destination are complemented and then multiplied and then
 replace the destination. The resultant color is always at least as light as
 either of the two constituent colors. Screening any color with white produces
 white. Screening any color with black leaves the original color unchanged.
' NB:Clamp results
'  Dc ' = (Sa.Da - (Da - Dc).(Sa - Sc)) + Sc.(1 - Da) + Dc.(1 - Sa)
'       = (Sc.Da + Dc.Sa - Sc.Dc) + Sc.(1 - Da) + Dc.(1 - Sa)
'       = Sc + Dc - Sc.Dc
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
            ' Dc ' = Sc + Dc - Sc.Dc
            lB = bDib(x, y)
            lB = lB + bDibDst(x, y)
            lB = lB - (bDib(x, y) * 1& * bDibDst(x, y)) / 255&
            If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB
            
            lG = bDib(x + 1, y)
            lG = lG + bDibDst(x + 1, y)
            lG = lG - (bDib(x + 1, y) * 1& * bDibDst(x + 1, y)) / 255&
            If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG
            
            lR = bDib(x + 2, y)
            lR = lR + bDibDst(x + 2, y)
            lR = lR - (bDib(x + 2, y) * 1& * bDibDst(x + 2, y)) / 255&
            If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
            
            
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
            
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4
   
   End If
   
End Sub
Public Sub PerformCompositeOverlay()
'Multiplies or screens the colors, dependent on the destination color. Source
 colors overlay the destination whilst preserving its highlights and shadows.
 The destination color is not replaced, but is mixed with the source color to
 reflect the lightness or darkness of the destination.
' NB:Clamp results
'  if 2.Dc < Da
'    Dc ' = 2.Sc.Dc + Sc.(1 - Da) + Dc.(1 - Sa)
'  otherwise
'    Dc ' = Sa.Da - 2.(Da - Dc).(Sa - Sc) + Sc.(1 - Da) + Dc.(1 - Sa)
'
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
            '  if 2.Dc < Da
            '    Dc ' = 2.Sc.Dc + Sc.(1 - Da) + Dc.(1 - Sa)
            '  otherwise
            '    Dc ' = Sa.Da - 2.(Da - Dc).(Sa - Sc) + Sc.(1 - Da) + Dc.(1 -
             Sa)
            If (2& * bDibDst(x, y) < bDibDst(x + 3, y)) Then
               lB = (2& * bDib(x, y) * bDibDst(x, y)) / 255&
               lB = lB + bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
               lB = lB + bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            Else
               lB = (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
               lB = lB - 2& * (bDibDst(x + 3, y) - bDibDst(x, y)) * (bDib(x +
                3, y) - bDib(x, y)) / 255&
               lB = lB + (bDib(x, y) * (255& - bDibDst(x + 3, y))) / 255&
               lB = lB + (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            End If
            If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB

            If (2& * bDibDst(x + 1, y) < bDibDst(x + 3, y)) Then
               lG = (2& * bDib(x + 1, y) * bDibDst(x + 1, y)) / 255&
               lG = lG + bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
               lG = lG + bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            Else
               lG = (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
               lG = lG - 2& * (bDibDst(x + 3, y) - bDibDst(x + 1, y)) * (bDib(x
                + 3, y) - bDib(x + 1, y)) / 255&
               lG = lG + (bDib(x + 1, y) * (255& - bDibDst(x + 3, y))) / 255&
               lG = lG + (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            End If
            If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG

            If (2& * bDibDst(x + 2, y) < bDibDst(x + 3, y)) Then
               lR = (2& * bDib(x + 2, y) * bDibDst(x + 2, y)) / 255&
               lR = lR + bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
               lR = lR + bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            Else
               lR = (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
               lR = lR - 2& * (bDibDst(x + 3, y) - bDibDst(x + 2, y)) * (bDib(x
                + 3, y) - bDib(x + 2, y)) / 255&
               lR = lR + (bDib(x + 2, y) * (255& - bDibDst(x + 3, y))) / 255&
               lR = lR + (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            End If
            If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
            
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDarken()
'Selects the darker of the destination and source colors. The destination is
 replaced with the source when the source is darker, otherwise it is left
 unchanged.
' NB:Clamp results
'  Dc ' = min(Sc.Da, Dc.Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
'  Da ' = Sa + Da - Sa.Da
'
'  or
'
'  if Sc.Da < Dc.Sa
'    src_over()
'  otherwise
'    dst_over()

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long, lC1 As Long, lC2 As
       Long
      Dim bUseSourceColour As Boolean
           
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
                        
            '  Dc ' = min(Sc.Da, Dc.Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
            
            ' Use the ITU grayscale standard to determine the colour value:
            lC1 = 71& * bDib(x, y)
            lC1 = lC1 + 707& * bDib(x + 1, y)
            lC1 = lC1 + 222& * bDib(x + 2, y)
            lC1 = lC1 * bDibDst(x + 3, y)
            
            lC2 = 71& * bDibDst(x, y)
            lC2 = lC2 + 707& * bDibDst(x + 1, y)
            lC2 = lC2 + 222& * bDibDst(x + 2, y)
            lC2 = lC2 * bDib(x + 3, y)
            
            If (lC1 < lC2) Then
               bUseSourceColour = True
            Else
               bUseSourceColour = False
            End If
            
            If (bUseSourceColour) Then
               lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lB = (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lB = lB + bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
            lB = lB + bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB
            
            If (bUseSourceColour) Then
               lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lG = (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lG = lG + bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
            lG = lG + bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG
            
            If (bUseSourceColour) Then
               lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lR = (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lR = lR + bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
            lR = lR + bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
                        
            
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeLighten()
'Selects the lighter of the destination and source colors. The destination is
 replaced with the source when the source is lighter, otherwise it is left
 unchanged.
' NB:Clamp results
'  Dc ' = max(Sc.Da, Dc.Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
'  Da ' = Sa + Da - Sa.Da
'
'  or
'
'  if Sc.Da > Dc.Sa
'    src_over()
'  otherwise
'    dst_over()

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long, lC1 As Long, lC2 As
       Long
      Dim bUseSourceColour As Boolean
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
         
            '  Dc ' = max(Sc.Da, Dc.Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
            
            lC1 = 71& * bDib(x, y)
            lC1 = lC1 + 707& * bDib(x + 1, y)
            lC1 = lC1 + 222& * bDib(x + 2, y)
            lC1 = lC1 * bDibDst(x + 3, y)
            
            lC2 = 71& * bDibDst(x, y)
            lC2 = lC2 + 706& * bDibDst(x + 1, y)
            lC2 = lC2 + 222& * bDibDst(x + 2, y)
            lC2 = lC2 * bDib(x + 3, y)
            
            If (lC1 > lC2) Then
               bUseSourceColour = True
            Else
               bUseSourceColour = False
            End If
            
            If (bUseSourceColour) Then
               lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lB = (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lB = lB + bDib(x, y) * (255& - bDibDst(x + 3, y)) / 255&
            lB = lB + bDibDst(x, y) * (255& - bDib(x + 3, y)) / 255&
            If (lB > 255) Then lB = 255
            bDibDst(x, y) = lB
            
            If (bUseSourceColour) Then
               lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lG = (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lG = lG + bDib(x + 1, y) * (255& - bDibDst(x + 3, y)) / 255&
            lG = lG + bDibDst(x + 1, y) * (255& - bDib(x + 3, y)) / 255&
            If (lG > 255) Then lG = 255
            bDibDst(x + 1, y) = lG
            
            If (bUseSourceColour) Then
               lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255&
            Else
               lR = (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255&
            End If
            lR = lR + bDib(x + 2, y) * (255& - bDibDst(x + 3, y)) / 255&
            lR = lR + bDibDst(x + 2, y) * (255& - bDib(x + 3, y)) / 255&
            If (lR > 255) Then lR = 255
            bDibDst(x + 2, y) = lR
                        
            
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDib(x + 3, y) * 1& * bDibDst(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeColorDodge()
'Brightens the destination color to reflect the source color. Painting with
 black produces no change.
' NB:Clamp results
'  if Sc.Da + Dc.Sa >= Sa.Da
'    Dc ' = Sa.Da + Sc.(1 - Da) + Dc.(1 - Sa)
'  otherwise
'    Dc ' = Dc.Sa/(1-Sc/Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
'
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      Dim lSaDa As Long, lC As Long, lSrcGrey As Long, lDstGrey As Long
      
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
            
            '  if Sc.Da + Dc.Sa >= Sa.Da
            '    Dc ' = Sa.Da + Sc.(1 - Da) + Dc.(1 - Sa)
            '  otherwise
            '    Dc ' = Dc.Sa/(1-Sc/Sa) + Sc.(1 - Da) + Dc.(1 - Sa)
            
            ' Note that the last two terms are the same in both cases.
            
            ' When doing the Sc.Da and Dc.Sa calculations, I'm using the ITU
            ' greyscale standard to determine the colour:
            lSaDa = bDib(x + 3, y)
            lSaDa = (lSaDa * bDibDst(x + 3, y)) / 255&
            lSrcGrey = (71& * bDib(x, y) + 707& * bDib(x + 1, y) + 222& *
             bDib(x + 2, y)) / 1000&
            lDstGrey = (71& * bDibDst(x, y) + 707& * bDibDst(x + 1, y) + 222& *
             bDibDst(x + 2, y)) / 1000&
            lC = (lSrcGrey * bDibDst(x + 3, y)) / 255& + (lDstGrey * bDib(x,
             y)) / 255&
            
            If (lC >= lSaDa) Then
               lB = ((lSaDa * bDib(x, y)) / 255& * bDibDst(x, y)) / 255&
               lG = ((lSaDa * bDib(x + 1, y)) / 255& * bDibDst(x + 1, y)) / 255&
               lR = ((lSaDa * bDib(x + 2, y)) / 255& * bDibDst(x + 2, y)) / 255&
            Else
               lB = ((lSaDa * bDib(x, y)) / 255& * bDibDst(x, y)) / 255&
               lG = ((lSaDa * bDib(x + 1, y)) / 255& * bDibDst(x + 1, y)) / 255&
               lR = ((lSaDa * bDib(x + 2, y)) / 255& * bDibDst(x + 2, y)) / 255&
                              
               ' TODO: what happens if Sa is 0, or if (1 - Sc/Sa) is 0?
               
               
            End If
                           
            lB = lB + (bDib(x, y) * (255& - bDibDst(x + 3, y))) / 255&
            lB = lB + (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            If (lB > 255) Then
               lB = 255
            End If
            bDibDst(x, y) = lB
            
            lG = lG + (bDib(x + 1, y) * (255& - bDibDst(x + 3, y))) / 255&
            lG = lG + (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            If (lG > 255) Then
               lG = 255
            End If
            bDibDst(x + 1, y) = lG
            
            lR = lR + (bDib(x + 2, y) * (255& - bDibDst(x + 3, y))) / 255&
            lR = lR + (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            If (lR > 255) Then
               lR = 255
            End If
            bDibDst(x + 2, y) = lR
            
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - lSaDa
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA


         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeColorBurn()
'Darkens the destination color to reflect the source color. Painting with white
 produces no change.
' NB:Clamp results
'  if Sc.Da + Dc.Sa <= Sa.Da
'    Dc ' = Sc.(1 - Da) + Dc.(1 - Sa)
'  otherwise
'    Dc ' = Sa.(Sc.Da + Dc.Sa - Sa.Da)/Sc + Sc.(1 - Da) + Dc.(1 - Sa)
'
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      Dim lSaDa As Long, lSrcGrey As Long, lDstGrey As Long, lC As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
            '  if Sc.Da + Dc.Sa <= Sa.Da
            '    Dc ' = Sc.(1 - Da) + Dc.(1 - Sa)
            '  otherwise
            '    Dc ' = Sa.(Sc.Da + Dc.Sa - Sa.Da)/Sc + Sc.(1 - Da) + Dc.(1 -
             Sa)
            '
            ' Note that the last two terms are the same in both cases.  Hence
            ' when Sc.Da + Dc.Sa > Sa.Da we do additional work
            
            ' When doing the Sc.Da and Dc.Sa calculations, I'm using the ITU
            ' greyscale standard to determine the colour:
            lSaDa = bDib(x + 3, y)
            lSaDa = (lSaDa * bDibDst(x + 3, y)) / 255&
            lSrcGrey = (71& * bDib(x, y) + 707& * bDib(x + 1, y) + 222& *
             bDib(x + 2, y)) / 1000&
            lDstGrey = (71& * bDibDst(x, y) + 707& * bDibDst(x + 1, y) + 222& *
             bDibDst(x + 2, y)) / 1000&
            lC = (lSrcGrey * bDibDst(x + 3, y)) / 255& + (lDstGrey * bDib(x,
             y)) / 255&
            
            If (lC > lSaDa) Then
               
               ' TODO: What should happen when Sc = 0?
               
               If (bDib(x, y) > 0) Then
                  lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255& +
                   (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255&
                  lB = (lB * bDib(x + 3, y)) / 255&
                  lB = lB / bDib(x, y)
               End If
               
               If (bDib(x + 1, y) > 0) Then
                  lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255& +
                   (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255&
                  lG = (lG * bDib(x + 3, y)) / 255&
                  lG = lG / bDib(x + 1, y)
               End If
               
               If (bDib(x + 2, y) > 0) Then
                  lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255& +
                   (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255&
                  lR = (lR * bDib(x + 3, y)) / 255&
                  lR = lR / bDib(x + 2, y)
               End If
            Else
               lB = 0
               lG = 0
               lR = 0
            End If
                           
            lB = lB + (bDib(x, y) * (255& - bDibDst(x + 3, y))) / 255&
            lB = lB + (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            If (lB > 255) Then
               lB = 255
            End If
            bDibDst(x, y) = lB
            
            lG = lG + (bDib(x + 1, y) * (255& - bDibDst(x + 3, y))) / 255&
            lG = lG + (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            If (lG > 255) Then
               lG = 255
            End If
            bDibDst(x + 1, y) = lG
            
            lR = lR + (bDib(x + 2, y) * (255& - bDibDst(x + 3, y))) / 255&
            lR = lR + (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            If (lR > 255) Then
               lR = 255
            End If
            bDibDst(x + 2, y) = lR
      
      
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - lSaDa
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeHardLight()
'Multiplies or screens the colors, dependent on the source color value. If the
 source color is lighter than 0.5, the destination is lightened as if it were
 screened. If the source color is darker than 0.5, the destination is darkened,
 as if it were multiplied. The degree of lightening or darkening is
 proportional to the difference between the source color and 0.5. If it is
 equal to 0.5 the destination is unchanged. Painting with pure black or white
 produces black or white.
' NB:Clamp results
'  if 2.Sc < Sa
'     Dc ' = 2.Sc.Dc + Sc.(1 - Da) + Dc.(1 - Sa)
'  otherwise
'     Dc ' = Sa.Da - 2.(Da - Dc).(Sa - Sc) + Sc.(1 - Da) + Dc.(1 - Sa)
'
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeSoftLight()
'Darkens or lightens the colors, dependent on the source color value. If the
 source color is lighter than 0.5, the destination is lightened. If the source
 color is darker than 0.5, the destination is darkened, as if it were burned
 in. The degree of darkening or lightening is proportional to the difference
 between the source color and 0.5. If it is equal to 0.5, the destination is
 unchanged. Painting with pure black or white produces a distinctly darker or
 lighter area, but does not result in pure black or white.
' NB:Clamp results
'  if 2.Sc < Sa
'     Dc ' = Dc.(Sa - (1 - Dc/Da).(2.Sc - Sa)) + Sc.(1 - Da) + Dc.(1 - Sa)
'  otherwise if Dc.8 <= Da
'     Dc ' = Dc.(Sa - (1 - Dc/Da).(2.Sc - Sa).(3 - 8.Dc/Da)) + Sc.(1 - Da) +
 Dc.(1 - Sa)
'  otherwise
'     Dc ' = (Dc.Sa + ((Dc/Da)^(0.5).Da - Dc).(2.Sc - Sa)) + Sc.(1 - Da) +
 Dc.(1 - Sa)
'
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeDifference()
'Subtracts the darker of the two constituent colors from the lighter. Painting
 with white inverts the destination color. Painting with black produces no
 change.
' NB:Clamp results
'  Dc ' = abs(Dc.Sa - Sc.Da) + Sc.(1 - Da) + Dc.(1 - Sa)
'      = Sc + Dc - 2.min(Sc.Da, Dc.Sa)
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
            '  Dc ' = abs(Dc.Sa - Sc.Da) + Sc.(1 - Da) + Dc.(1 - Sa)
            '      = Sc + Dc - 2.min(Sc.Da, Dc.Sa)
            lB = Abs((bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255& - _
                  (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255&)
            lB = lB + (bDib(x, y) * (255& - bDibDst(x + 3, y))) / 255&
            lB = lB + (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            If (lB > 255) Then
               lB = 255
            End If
            bDibDst(x, y) = lB

            lG = Abs((bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255& - _
                  (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255&)
            lG = lG + (bDib(x + 1, y) * (255& - bDibDst(x + 3, y))) / 255&
            lG = lG + (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            If (lG > 255) Then
               lG = 255
            End If
            bDibDst(x + 1, y) = lG

            lR = Abs((bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255& - _
                  (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255&)
            lR = lR + (bDib(x + 2, y) * (255& - bDibDst(x + 3, y))) / 255&
            lR = lR + (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            If (lR > 255) Then
               lR = 255
            End If
            bDibDst(x + 2, y) = lR


            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDibDst(x + 3, y) * 1& * bDib(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub
Public Sub PerformCompositeExclusion()
'Produces an effect similar to that of 'difference', but appears as lower
 contrast. Painting with white inverts the destination color. Painting with
 black produces no change.
' NB:Clamp results
'  Dc ' = (Sc.Da + Dc.Sa - 2.Sc.Dc) + Sc.(1 - Da) + Dc.(1 - Sa)
'  Da ' = Sa + Da - Sa.Da

Dim srcX As Long
Dim srcY As Long
Dim srcWidth As Long
Dim srcHeight As Long

   If getSourceDimensions(srcX, srcY, srcWidth, srcHeight) Then

      Dim bDib() As Byte
      Dim bDibDst() As Byte
      Dim tSA As SAFEARRAY2D
      Dim tSADst As SAFEARRAY2D
    
      ' Get the bits in the from DIB section:
      With tSA
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibSrc.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibSrc.BytesPerScanLine
          .pvData = m_cDibSrc.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDib()), VarPtr(tSA), 4
   
      ' Get the bits in the from DIB section:
      With tSADst
          .cbElements = 1
          .cDims = 2
          .Bounds(0).lLbound = 0
          .Bounds(0).cElements = m_cDibDst.height
          .Bounds(1).lLbound = 0
          .Bounds(1).cElements = m_cDibDst.BytesPerScanLine()
          .pvData = m_cDibDst.DIBSectionBitsPtr
      End With
      CopyMemory ByVal VarPtrArray(bDibDst()), VarPtr(tSADst), 4
   
   
      Dim x As Long
      Dim y As Long
      Dim xEnd As Long
      Dim yEnd As Long
   
      xEnd = srcX + srcWidth - 1
      yEnd = srcY + srcHeight - 1
      
      Dim lR As Long, lG As Long, lB As Long, lA As Long
      
      For x = srcX To xEnd Step 4
         For y = srcY To yEnd
      
            
            '  Dc ' = (Sc.Da + Dc.Sa - 2.Sc.Dc) + Sc.(1 - Da) + Dc.(1 - Sa)
            lB = (bDib(x, y) * 1& * bDibDst(x + 3, y)) / 255&
            lB = lB + (bDibDst(x, y) * 1& * bDib(x + 3, y)) / 255&
            lB = lB - 2& * (bDib(x, y) * 1& * bDibDst(x, y)) / 255&
            lB = lB + (bDib(x, y) * (255& - bDibDst(x + 3, y))) / 255&
            lB = lB + (bDibDst(x, y) * (255& - bDib(x + 3, y))) / 255&
            If (lB > 255) Then
               lB = 255
            End If
            bDibDst(x, y) = lB
      
            lG = (bDib(x + 1, y) * 1& * bDibDst(x + 3, y)) / 255&
            lG = lG + (bDibDst(x + 1, y) * 1& * bDib(x + 3, y)) / 255&
            lG = lG - 2& * (bDib(x + 1, y) * 1& * bDibDst(x + 1, y)) / 255&
            lG = lG + (bDib(x + 1, y) * (255& - bDibDst(x + 3, y))) / 255&
            lG = lG + (bDibDst(x + 1, y) * (255& - bDib(x + 3, y))) / 255&
            If (lG > 255) Then
               lG = 255
            End If
            bDibDst(x + 1, y) = lG
      
            lR = (bDib(x + 2, y) * 1& * bDibDst(x + 3, y)) / 255&
            lR = lR + (bDibDst(x + 2, y) * 1& * bDib(x + 3, y)) / 255&
            lR = lR - 2& * (bDib(x + 2, y) * 1& * bDibDst(x + 2, y)) / 255&
            lR = lR + (bDib(x + 2, y) * (255& - bDibDst(x + 3, y))) / 255&
            lR = lR + (bDibDst(x + 2, y) * (255& - bDib(x + 3, y))) / 255&
            If (lR > 255) Then
               lR = 255
            End If
            bDibDst(x + 2, y) = lR
      
      
            '  Da ' = Sa + Da - Sa.Da
            lA = bDib(x + 3, y)
            lA = lA + bDibDst(x + 3, y)
            lA = lA - (bDibDst(x + 3, y) * 1& * bDib(x + 3, y)) / 255&
            If (lA > 255) Then lA = 255
            bDibDst(x + 3, y) = lA
      
         Next y
      Next x
      
      
      CopyMemory ByVal VarPtrArray(bDibDst), 0&, 4
      CopyMemory ByVal VarPtrArray(bDib), 0&, 4

   End If
   
End Sub

Private Function getSourceDimensions( _
      ByRef srcX As Long, _
      ByRef srcY As Long, _
      ByRef srcWidth As Long, _
      ByRef srcHeight As Long _
   ) As Boolean
   
   ' Return allowable dimensions for the source
   ' depending on the size of the destination.
   srcX = m_srcX
   srcY = m_srcY
   srcWidth = m_srcWidth
   srcHeight = m_srcHeight
   If (srcWidth <= 0) Then
      srcWidth = m_cDibSrc.width
   End If
   If (srcHeight <= 0) Then
      srcHeight = m_cDibSrc.height
   End If
   If (srcX > m_cDibDst.width) Then
      ' nothing to do
      getSourceDimensions = False
      Exit Function
   End If
   If (srcY > m_cDibDst.height) Then
      getSourceDimensions = False
      Exit Function
   End If
   If (srcX < 0) Then
      srcX = 0
   End If
   If (srcY < 0) Then
      srcY = 0
   End If
   If (srcX + srcWidth > m_cDibDst.width) Then
      srcWidth = m_cDibDst.width - srcX
   End If
   If (srcY + srcHeight > m_cDibDst.height) Then
      srcHeight = m_cDibDst.height - srcY
   End If
   
   ' Bytes per scan line:
   srcX = srcX * 4
   srcWidth = srcWidth * 4
   
   getSourceDimensions = True
   
End Function


   
Private Sub Class_Initialize()
   '
   m_srcWidth = -1
   m_srcHeight = -1
   '
End Sub