VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "Graphics"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

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 RGBQUAD
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
    rgbAlpha As Byte
End Type

Private Type BITMAPINFOHEADER
    bmSize As Long
    bmWidth As Long
    bmHeight As Long
    bmPlanes As Integer
    bmBitCount As Integer
    bmCompression As Long
    bmSizeImage As Long
    bmXPelsPerMeter As Long
    bmYPelsPerMeter As Long
    bmClrUsed As Long
    bmClrImportant As Long
End Type

Private Type BITMAPINFO
    bmHeader As BITMAPINFOHEADER
    bmColors(0 To 255) As RGBQUAD
End Type

Private Type Color
    Red As Long
    Green As Long
    Blue As Long
    Alpha As Long
End Type

Private Type RotateCoordenats
    RotatedX As Long
    RotatedY As Long
End Type

Public Enum MirrorState
    None = 0
    Horizontal = 1
    Vertical = 2
    HorizontalVertical = 3
End Enum


Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" _
(ByVal hObject As Long, ByVal nCount As Long, ByRef lpObject As Any) _
As Long

Private Declare Function GetDIBits Lib "gdi32" (ByVal hDC 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 StretchDIBits Lib "gdi32" (ByVal hDC As Long, _
ByVal X As Long, ByVal Y As Long, ByVal dWidth As Long, ByVal dHeight _
As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal SrcWidth As _
Long, ByVal SrcHeight As Long, lpBits As Any, lpBI As BITMAPINFO, _
ByVal wUsage As Long, ByVal RasterOp As Long) As Long

Dim ImageData() As Byte
Dim ImageDataChanged() As Byte
Dim ImageDataMask() As Byte
Dim blnTransparent As Boolean
Dim bm As BITMAP
Dim bmi As BITMAPINFO
Dim bmLen As Long
Dim X As Long
Dim Y As Long
Dim lngBackColor As Long
Dim lngOldBackColor As Long
Dim lngTransparentColor As Long
Dim lngNewColor As Long
Dim lngOldColor As Long
Dim lngRotate As Long
Dim lngWidthImage As Long
Dim lngHeigthImage As Long
Dim msMirrorState As MirrorState
Dim blnBlackAndWhite As Boolean
Dim lngTransparentBlackAndWhiteColor As Long
Private Const PI As Single = 3.14159265

Private Function ByteAlignOnWord(ByVal bitDepth As Byte, ByVal Width As Long) As Long
    ' function to align any bit depth on dWord boundaries
    ByteAlignOnWord = (((Width * bitDepth) + &H1F&) And Not &H1F&) \ &H8&
End Function

Private Function RGBValues(ByVal Color As Long) As Color 'find the rgb color values of a color
    Dim ReturnColor As Color
    With ReturnColor
        .Red = Color And 255
        .Green = (Color And 65535) \ 256
        .Blue = (Color And &HFF0000) \ 65536
        .Alpha = ((Color And &HFF000000) \ 16777216) And &HFF
    End With
    RGBValues = ReturnColor
End Function

Public Function GrayScale(ByVal lColor As Long) As Long
    GrayScale = ((77& * (lColor And &HFF&) + _
                 152& * (lColor And &HFF00&) \ &H100& + _
                  28& * (lColor \ &H10000)) \ 256&) * &H10101
End Function

Private Function InvRotateCoord(ByVal X As Long, ByVal Y As Long, _
  ByVal X0 As Long, ByVal Y0 As Long, _
  ByVal Angle As Single) As RotateCoordenats
    Dim SinA As Single, CosA As Single
    
    'convert X,Y screen positions to math positions
    X = X - X0 - 3
    Y = Y - Y0 - 3
    
    'convert the angle to angles values
    Angle = Angle * PI / 180
    
    'calculate the SIN and COS of an angle
    SinA = Sin(Angle)
    CosA = Cos(Angle)
    
    'Calculate the X,Y Rotated coordenats
    InvRotateCoord.RotatedX = X0 + X * CosA - Y * SinA
    InvRotateCoord.RotatedY = Y0 + Y * CosA + X * SinA
End Function


'Routine to get an image's pixel information into an array dimensioned (rgb, x, y)
Public Sub GetImageData(ByRef SrcPictureBox As Control)
      
    bmi.bmHeader.bmSize = 40 'Size, in bytes, of the header (always 40)
    bmi.bmHeader.bmPlanes = 1 'Number of planes (always one)
    bmi.bmHeader.bmBitCount = 24 'Bits per pixel (always 24 for image processing)
    bmi.bmHeader.bmCompression = 0 'Compression: none or RLE (always zero)

    'Calculate the size of the bitmap type (in bytes)
    
    bmLen = Len(bm)

    'Get the picture box information from SrcPictureBox and put it into our 'bm' variable
    GetObject SrcPictureBox.Image, bmLen, bm
    
    'Build a correctly sized array.
    ReDim ImageData(0 To ByteAlignOnWord(24, bm.bmWidth) - 1, 0 To bm.bmHeight - 1)

    'Finish building the 'bmi' variable we want to pass to the GetDIBits call (the same variable we used above)
    bmi.bmHeader.bmWidth = bm.bmWidth
    bmi.bmHeader.bmHeight = bm.bmHeight

    'Now that we've completely filled up the 'bmi' variable, we use GetDIBits to take the data from SrcPictureBox and put it into the ImageData() array using the settings we specified in 'bmi'
    GetDIBits SrcPictureBox.hDC, SrcPictureBox.Image, 0, bm.bmHeight, ImageData(0, 0), bmi, 0
    lngBackColor = RGB(ImageData(2, 0), ImageData(1, 0), ImageData(0, 0))
    lngOldBackColor = RGB(ImageData(2, 0), ImageData(1, 0), ImageData(0, 0))
    lngTransparentColor = RGB(ImageData(2, 0), ImageData(1, 0), ImageData(0, 0))
End Sub

'Routine to set an image's pixel information from an array dimensioned(rgb, x, y)
Public Sub DrawImageData(ByRef DstPictureBox As Control, Optional ByRef X As Long = 0, Optional ByRef Y As Long = 0)
    
    Dim blnAutoRedraw As Boolean
          
    If DstPictureBox.AutoRedraw = False Then
        blnAutoRedraw = True
        DstPictureBox.AutoRedraw = True
    Else
        blnAutoRedraw = False
    End If
    
    Call ChangeImage
    
    If blnTransparent = False Then
        If msMirrorState = None Then
            StretchDIBits DstPictureBox.hDC, X, Y, lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcCopy
        ElseIf msMirrorState = Horizontal Then
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, Y, -lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcCopy
        ElseIf msMirrorState = Vertical Then
            StretchDIBits DstPictureBox.hDC, X, lngHeigthImage + Y, lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, bm.bmHeight, ImageDataChanged(0, 0), bmi, 0, vbSrcCopy
        ElseIf msMirrorState = HorizontalVertical Then
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, lngHeigthImage + Y, -lngWidthImage, -bm.bmHeight, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageData(0, 0), bmi, 0, vbSrcCopy
        End If
    Else
        If msMirrorState = None Then
            StretchDIBits DstPictureBox.hDC, X, Y, lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
            StretchDIBits DstPictureBox.hDC, X, Y, bm.bmWidth, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataMask(0, 0), bmi, 0, vbSrcAnd
            StretchDIBits DstPictureBox.hDC, X, Y, lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
        ElseIf msMirrorState = Horizontal Then
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, Y, -lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, Y, -lngWidthImage, lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataMask(0, 0), bmi, 0, vbSrcAnd
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, Y, -lngWidthImage, bm.bmHeight, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
        ElseIf msMirrorState = Vertical Then
            StretchDIBits DstPictureBox.hDC, X, bm.bmHeight + Y, lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
            StretchDIBits DstPictureBox.hDC, X, lngHeigthImage + Y, lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataMask(0, 0), bmi, 0, vbSrcAnd
            StretchDIBits DstPictureBox.hDC, X, bm.bmHeight + Y, lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
         ElseIf msMirrorState = HorizontalVertical Then
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, lngHeigthImage + Y, -lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, lngHeigthImage + Y, -lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataMask(0, 0), bmi, 0, vbSrcAnd
            StretchDIBits DstPictureBox.hDC, lngWidthImage + X, lngHeigthImage + Y, -lngWidthImage, -lngHeigthImage, 0, 0, _
                lngWidthImage, lngHeigthImage, ImageDataChanged(0, 0), bmi, 0, vbSrcInvert
        End If
    End If
    
    DstPictureBox.Picture = DstPictureBox.Image
    If blnAutoRedraw = True Then DstPictureBox.AutoRedraw = False
End Sub

Public Property Get Transparent() As Boolean
    Transparent = blnTransparent
End Property

Public Property Let Transparent(ByVal vNewValue As Boolean)
    blnTransparent = vNewValue
End Property

Public Property Get BlackAndWhite() As Boolean
    BlackAndWhite = blnBlackAndWhite
End Property

Public Property Let BlackAndWhite(ByVal vNewValue As Boolean)
    blnBlackAndWhite = vNewValue
End Property

Public Property Get Mirror() As MirrorState
    Transparent = blnTransparent
End Property

Public Property Let Mirror(ByVal vNewValue As MirrorState)
    msMirrorState = vNewValue
End Property

Public Property Get Width() As Long
    Width = bmi.bmHeader.bmWidth
End Property

Public Property Get Height() As Long
    Height = bmi.bmHeader.bmHeight
End Property

Public Property Get BackColor() As Long
    BackColor = lngBackColor
End Property

Public Property Let BackColor(ByVal vNewValue As Long)
    If vNewValue = -1 Then
        lngBackColor = lngOldBackColor
    Else
        lngBackColor = vNewValue
    End If
End Property

Public Property Get TransparentColor() As Long
    TransparentColor = lngTransparentColor
End Property

Public Property Let OldColor(ByVal vNewValue As Long)
    lngOldColor = vNewValue
End Property

Public Property Get OldColor() As Long
    OldColor = lngOldColor
End Property

Public Property Let NewColor(ByVal vNewValue As Long)
    lngNewColor = vNewValue
End Property

Public Property Get NewColor() As Long
    NewColor = lngNewColor
End Property

Public Property Let Rotate(ByVal vNewValue As Long)
    lngRotate = vNewValue
End Property

Public Property Get Rotate() As Long
    Rotate = lngRotate
End Property

Public Property Let TransparentColor(ByVal vNewValue As Long)
    If vNewValue = -1 Then
        lngTransparentColor = lngOldBackColor
    Else
        lngTransparentColor = vNewValue
    End If
End Property

Private Sub ChangeImage()
    Dim clrWhite As Color
    Dim clrBlack As Color
    Dim clrNewColor As Color
    Dim clrOldColor As Color
    Dim clrBackColor As Color
    Dim clrOldBackColor As Color
    Dim clrTransparentColor As Color
    Dim clrConvertToBlackAndWhite As Color
    Dim lngConvertToBlackAndWhite As Long
    Dim RWhite As Byte
    Dim GWhite As Byte
    Dim BWhite As Byte
    Dim RBlack As Byte
    Dim GBlack As Byte
    Dim BBlack As Byte
    Dim RC As RotateCoordenats
    
    
    'On Error Resume Next
    
    If lngBackColor = -1 Then lngBackColor = lngOldBackColor
    
    clrOldBackColor = RGBValues(lngBackColor)
    
    clrBackColor = RGBValues(lngBackColor)
    
    clrNewColor = RGBValues(lngNewColor)
    clrOldColor = RGBValues(lngOldColor)
                
    
    clrWhite = RGBValues(vbWhite)
    clrBlack = RGBValues(vbBlack)
    RWhite = vbWhite And &HFF&
    GWhite = (vbWhite And &HFF00&) \ &H100&
    BWhite = (vbWhite And &HFF0000) \ &H10000
    RBlack = vbBlack And &HFF&
    GBlack = (vbBlack And &HFF00&) \ &H100&
    BBlack = (vbBlack And &HFF0000) \ &H10000
      
    If lngRotate <> 0 Then
        If bm.bmWidth > bm.bmHeight Then
            ReDim ImageDataChanged(0 To ByteAlignOnWord(24, bm.bmWidth) - 1, 0 To bm.bmWidth - 1)
            lngWidthImage = bm.bmWidth
            lngHeigthImage = bm.bmWidth
        ElseIf bm.bmWidth < bm.bmHeight Then
            ReDim ImageDataChanged(0 To ByteAlignOnWord(24, bm.bmHeight) - 1, 0 To bm.bmHeight - 1)
            lngWidthImage = bm.bmHeight
            lngHeigthImage = bm.bmHeight
        End If
    Else
        ReDim ImageDataChanged(0 To ByteAlignOnWord(24, bm.bmWidth) - 1, 0 To bm.bmHeight - 1)
        lngWidthImage = bm.bmWidth
        lngHeigthImage = bm.bmHeight
    End If
    ReDim ImageDataMask(0 To ByteAlignOnWord(24, lngWidthImage) - 1, 0 To lngHeigthImage - 1)
    For X = 0 To ByteAlignOnWord(bmi.bmHeader.bmBitCount, lngWidthImage) - 3 Step 3
        For Y = 0 To lngHeigthImage - 1
            'Rotate an image
            If lngRotate <> 0 Then
                RC = InvRotateCoord(X, Y, lngWidthImage / 2, lngHeigthImage / 2, lngRotate)
                If RC.RotatedX <= 0 Or RC.RotatedX >= bm.bmWidth Or RC.RotatedY <= 0 Or RC.RotatedY >= bm.bmHeight Then
                    'do nothing
                Else
                    ImageDataChanged(X + 2, Y) = ImageData(RC.RotatedX + 2, RC.RotatedY)
                    ImageDataChanged(X + 1, Y) = ImageData(RC.RotatedX + 1, RC.RotatedY)
                    ImageDataChanged(X, Y) = ImageData(RC.RotatedX, RC.RotatedY)
                    If RGB(ImageDataChanged(X + 2, Y), ImageDataChanged(X + 1, Y), ImageDataChanged(X, Y)) = &HFFFF Or X >= bm.bmWidth Or Y >= bm.bmHeight Then
                        ImageDataChanged(X + 2, Y) = clrOldBackColor.Red
                        ImageDataChanged(X + 1, Y) = clrOldBackColor.Green
                        ImageDataChanged(X, Y) = clrOldBackColor.Blue
                    End If
                End If
            Else
                ImageDataChanged(X + 2, Y) = ImageData(X + 2, Y)
                ImageDataChanged(X + 1, Y) = ImageData(X + 1, Y)
                ImageDataChanged(X, Y) = ImageData(X, Y)
            End If
            
            'change image backcolor
            If ImageDataChanged(X + 2, Y) = clrOldBackColor.Red And ImageDataChanged(X + 1, Y) = clrOldBackColor.Green And ImageDataChanged(X, Y) = clrOldBackColor.Blue Then
                ImageDataChanged(X + 2, Y) = clrBackColor.Red
                ImageDataChanged(X + 1, Y) = clrBackColor.Green
                ImageDataChanged(X, Y) = clrBackColor.Blue
            End If
            
            'change image Color
            If lngOldColor <> lngNewColor Then
                If ImageDataChanged(X + 2, Y) = clrOldColor.Red And ImageDataChanged(X + 1, Y) = clrOldColor.Green And ImageDataChanged(X, Y) = clrOldColor.Blue Then
                    ImageDataChanged(X + 2, Y) = clrNewColor.Red
                    ImageDataChanged(X + 1, Y) = clrNewColor.Green
                    ImageDataChanged(X, Y) = clrNewColor.Blue
                End If
            End If
            
            'Black and White
            If blnBlackAndWhite = True Then
                lngConvertToBlackAndWhite = GrayScale(RGB(ImageDataChanged(X + 2, Y), ImageDataChanged(X + 1, Y), ImageDataChanged(X, Y)))
                clrConvertToBlackAndWhite = RGBValues(lngConvertToBlackAndWhite)
                ImageDataChanged(X + 2, Y) = clrConvertToBlackAndWhite.Red
                ImageDataChanged(X + 1, Y) = clrConvertToBlackAndWhite.Green
                ImageDataChanged(X, Y) = clrConvertToBlackAndWhite.Blue
            End If
            
            'mask for transparency
            If blnTransparent = True Then
                If blnBlackAndWhite = False Then
                    clrTransparentColor = RGBValues(lngTransparentColor)
                Else
                    lngTransparentBlackAndWhiteColor = GrayScale(lngTransparentColor)
                    clrTransparentColor = RGBValues(lngTransparentBlackAndWhiteColor)
                End If
                If ImageDataChanged(X + 2, Y) = clrTransparentColor.Red And ImageDataChanged(X + 1, Y) = clrTransparentColor.Green And ImageDataChanged(X, Y) = clrTransparentColor.Blue Then
                    ImageDataMask(X + 2, Y) = clrWhite.Red
                    ImageDataMask(X + 1, Y) = clrWhite.Green
                    ImageDataMask(X, Y) = clrWhite.Blue
                Else
                    ImageDataMask(X + 2, Y) = clrBlack.Red
                    ImageDataMask(X + 1, Y) = clrBlack.Green
                    ImageDataMask(X, Y) = clrBlack.Blue
                End If
            End If
        Next Y
    Next X
End Sub
