Atlanta Custom Software Development 

 
   Search        Code/Page
 

User Login
Email

Password

 

Forgot the Password?
Services
» Web Development
» Maintenance
» Data Integration/BI
» Information Management
Programming
  Database
Automation
OS/Networking
Graphics
Links
Tools
» Regular Expr Tester
» Free Tools


Click here to copy the following block
' This structure holds Bitmap information
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

' This structure holds SAFEARRAY info
Private Type SafeArray2
  cDims As Integer
  fFeatures As Integer
  cbElements As Long
  cLocks As Long
  pvData As Long
  cElements1 As Long
  lLbound1 As Long
  cElements2 As Long
  lLbound2 As Long
End Type

' API declares
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As _
  Any, pSrc As Any, ByVal ByteLen As Long)
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal _
  hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

' Rotate a 256-color bitmap by any angle:
'  sourcePB is the source PictureBox control (may be hidden)
'  destPB is the destination PictureBox control
'  XC, YC are the coordinates of the rotation center
'  ANGLE is the rotation angle in degrees

' this improved version scans only a portion of the image, and builds
' remaining points using simmetry. This algorithm is particularly efficient
' when the
' center of the rotation is inside the bitmap, the best performances are
' achieved
' when it is near to the center of the bitmap. Moreover, this code saves some
' CPU time by using pre-calculated values for SIN, COS, and SQR functions.

' IMPORTANT: the source and destination PictureBox control must initially
' contain the *same* bitmap, to ensure that size and color palette
' are correctly initialized.

' Example:
'  'Load the same image in both source (hidden) and destination controls
'  Picture1.Picture = LoadPicture("d:\winnt\gone fishing.bmp")
'  Picture2.Picture = LoadPicture("d:\winnt\gone fishing.bmp")
'  ' Rotate by 360°
'  Dim a As Single
'  For a = 0 To 360 Step 5
'    RotatePicture2 Picture1, Picture2, 50, 50, a
'  Next

Private Sub RotatePicture2(sourcePB As PictureBox, destPB As PictureBox, _
  xc As Long, yc As Long, degrees As Single)

  ' all angles are expressed in 1/10000ths of radians
  Const PI As Long = 31416
  Const HALFPI As Long = 15707
  Const DOUBLEPI As Long = 62831
  
  Const SQRTABLE_MAX As Long = 40000
  
  Static sinTable() As Single
  Static atnTable() As Long
  Static sqrTable() As Single
  Static initialized As Boolean
  
  ' these are used to address the pixel using matrices
  Dim pict1() As Byte
  Dim pict2() As Byte
  Dim p1 As SafeArray2, p2 As SafeArray2
  Dim bmp1 As BITMAP, bmp2 As BITMAP
  ' these are used by the rotating algorithm
  Dim radians As Long
  Dim angle As Long
  Dim angle0 As Long
  Dim distance As Single
  Dim distanceSquared As Long
  Dim deltaX As Long, deltaY As Long
  Dim deltaXSquared As Single, deltaX10000 As Long
  Dim x As Long, y As Long
  Dim dx As Long, dy As Long
  Dim x0 As Long, y0 As Long
  Dim xx As Long, yy As Long
  Dim xStart As Long, xEnd As Long
  Dim yStart As Long, yEnd As Long
  Dim bmWidth1 As Long
  Dim bmHeight1 As Long
  
  ' Initialize sin,cos,sqr tables
  If Not initialized Then
    initialized = True
    
    Dim i As Long
    ' evaluate a table of sin for 360+90 degrees
    ' with a precision of 1/10000 of a radian
    ' this permits to reuse the same table for cosine, too
    ' since COX(x) = SIN(x + 90°)
    ReDim sinTable(0 To 62831 + 15709) As Single
    For i = 0 To UBound(sinTable)
      sinTable(i) = Sin(i / 10000)
    Next
    
    ' evaluate a table for Atn(x)*10000 for x=[0,1], with steps of 0,0001
    ReDim atnTable(0 To 10000) As Long
    For i = LBound(atnTable) To UBound(atnTable)
      atnTable(i) = Atn(i / 10000) * 10000#
    Next
    
    ' evaluate a table for Sqr(i)
    ReDim sqrTable(SQRTABLE_MAX) As Single
    For i = 0 To SQRTABLE_MAX
      sqrTable(i) = Sqr(i)
    Next
  End If
  
  ' get bitmap info
  GetObjectAPI sourcePB.Picture, Len(bmp1), bmp1
  GetObjectAPI destPB.Picture, Len(bmp2), bmp2

  If bmp1.bmPlanes <> 1 Or bmp1.bmBitsPixel <> 8 Or bmp2.bmPlanes <> 1 Or _
    bmp2.bmBitsPixel <> 8 Then
    MsgBox "This routine supports 256-color bitmaps only", vbCritical
    Exit Sub
  End If
  
  ' have the local matrices point to bitmap pixels
  With p1
    .cbElements = 1
    .cDims = 2
    .lLbound1 = 0
    .cElements1 = bmp1.bmHeight
    .lLbound2 = 0
    .cElements2 = bmp1.bmWidthBytes
    .pvData = bmp1.bmBits
  End With
  CopyMemory ByVal VarPtrArray(pict1), VarPtr(p1), 4
  
  With p2
    .cbElements = 1
    .cDims = 2
    .lLbound1 = 0
    .cElements1 = bmp2.bmHeight
    .lLbound2 = 0
    .cElements2 = bmp2.bmWidthBytes
    .pvData = bmp2.bmBits
  End With
  CopyMemory ByVal VarPtrArray(pict2), VarPtr(p2), 4
  
  ' convert the angle into 1/10000ths of radians
  ' subtracting 628310000 ensure that when radians is used in the
  ' subtraction in the loop, it produces a positive number
  radians = degrees / (180 / 3.14159) * 10000& - 628310000
  
  ' we have several cases, depending on where XC falls
  ' compared to the center of the image
  If xc < bmp2.bmWidth \ 2 Then
    xStart = xc
    xEnd = bmp2.bmWidth - 1
  Else
    xStart = 0
    xEnd = xc
  End If

  If yc < bmp2.bmHeight \ 2 Then
    yStart = yc
    yEnd = bmp2.bmWidth - 1
  Else
    yStart = 0
    yEnd = yc
  End If
  
  ' the main loop of this routine scans a squared portion
  ' of the image whose corners falls on the rotation center
  ' Of the four squares that touch the rotation center, here
  ' we choose the one with the highest number of pixels
  ' withing the image
  
  If xEnd - xStart > yEnd - yStart Then
    If yStart = 0 Then
      yStart = yEnd - (xEnd - xStart)
    Else
      yEnd = yStart + (xEnd - xStart)
    End If
  Else
    If xStart = 0 Then
      xStart = xEnd - (yEnd - yStart)
    Else
      xEnd = xStart + (yEnd - yStart)
    End If
  End If

  bmWidth1 = bmp1.bmWidth
  bmHeight1 = bmp1.bmHeight
  
  ' rotate the picture
  
  For x = xStart To xEnd
    ' these values are loop invariant for the following For-Next
    deltaX = x - xc
    deltaXSquared = deltaX * deltaX
    deltaX10000 = deltaX * 10000

    For y = yStart To yEnd
      deltaY = y - yc
      
      ' evaluate the arc-tangent of (deltaY/deltaX)
      ' many IFs are required, since the atnTable() array only
      ' covers the range [0,1] - if (deltaY/deltaX) is > 1 we
      ' must use its reciprocal deltaX/deltaY
      If deltaX > 0 Then
        If deltaY >= 0 Then
          If deltaY < deltaX Then
            angle = atnTable((deltaY * 10000) \ deltaX)
          Else
            angle = HALFPI - atnTable(deltaX10000 \ deltaY)
          End If
        Else
          If -deltaY < deltaX Then
            angle = -atnTable((deltaY * -10000) \ deltaX)
          Else
            angle = -HALFPI + atnTable(-deltaX10000 \ deltaY)
          End If
        End If
      ElseIf deltaX < 0 Then
        If deltaY > 0 Then
          If deltaY < -deltaX Then
            angle = PI - atnTable((deltaY * -10000) \ deltaX)
          Else
            angle = HALFPI + atnTable(-deltaX10000 \ deltaY)
          End If
        Else
          If deltaY > deltaX Then
            angle = PI + atnTable((deltaY * 10000) \ deltaX)
          Else
            angle = -HALFPI - atnTable(deltaX10000 \ deltaY)
          End If
        End If
      Else
        If deltaY >= 0 Then
          angle = HALFPI
        Else
          angle = -HALFPI
        End If
      End If
      ' --- end of arc-tangent evaluation
        
      ' "angle" is the angle of the segment that goes from
      ' the center to (x,y) - since we wish to evaluate the
      ' color of this point, we must check the point in the
      ' original bitmap that has the same distance from the
      ' center but with a different angle
        
      ' evaluate the distance of (x,y) from the rotation
      ' center, using if possible the value already stored
      ' in sqrTable()
      distanceSquared = deltaXSquared + deltaY * deltaY
      If distanceSquared <= SQRTABLE_MAX Then
        distance = sqrTable(distanceSquared)
      Else
        distance = Sqr(distanceSquared)
      End If
      
      ' the old point in the original bitmap has same
      ' distance but a different angle
      angle0 = (angle - radians) Mod DOUBLEPI
      
      ' evaluate the x,y offset of the old point from
      ' the rotation center
      dx = distance * sinTable(angle0 + HALFPI) ' really cosine
      dy = distance * sinTable(angle0)
      
      ' if (x,y) falls within the image
      If x >= 0 And x < bmWidth1 And y >= 0 And y < bmHeight1 Then
        ' (x0,y0) is the corresponding point in the original bitmap
        x0 = xc + dx
        y0 = yc + dy
        ' if (x0,y0) falls within the bitmap boundaries, copy the pixel
        ' else, set the (x,y) pixel to zero (background color)
        If x0 >= 0 And x0 < bmWidth1 And y0 >= 0 And y0 < bmHeight1 Then
          pict2(x, y) = pict1(x0, y0)
        Else
          pict2(x, y) = 0
        End If
      
        ' this is the point simmetrical to the rotation center - this
        ' block is within the outer If clause because the simmetrical
        ' point can be within the bitmap only if (x,y) was within the
        ' bitmap too
        xx = xc - deltaX
        yy = yc - deltaY
        If xx >= 0 And xx < bmWidth1 And yy >= 0 And yy < bmHeight1 Then
          x0 = xc - dx
          y0 = yc - dy
          If x0 >= 0 And x0 < bmWidth1 And y0 >= 0 And y0 < bmHeight1 _
            Then
            pict2(xx, yy) = pict1(x0, y0)
          Else
            pict2(xx, yy) = 0
          End If
        End If
      
      End If
      
      ' now deal with the pixel 90° ahead of the one in (x,y)
      xx = xc + deltaY
      yy = yc - deltaX
      If xx >= 0 And xx < bmWidth1 And yy >= 0 And yy < bmHeight1 Then
        x0 = xc + dy
        y0 = yc - dx
        If x0 >= 0 And x0 < bmWidth1 And y0 >= 0 And y0 < bmHeight1 Then
          pict2(xx, yy) = pict1(x0, y0)
        Else
          pict2(xx, yy) = 0
        End If
      End If

      ' now deal with the pixel 270° ahead of the one in (x,y)
      xx = xc - deltaY
      yy = yc + deltaX
      If xx >= 0 And xx < bmWidth1 And yy >= 0 And yy < bmHeight1 Then
        x0 = xc - dy
        y0 = yc + dx
        If x0 >= 0 And x0 < bmWidth1 And y0 >= 0 And y0 < bmHeight1 Then
          pict2(xx, yy) = pict1(x0, y0)
        Else
          pict2(xx, yy) = 0
        End If
      End If
    Next
  Next
  
  ' release arrays
  CopyMemory ByVal VarPtrArray(pict1), 0&, 4
  CopyMemory ByVal VarPtrArray(pict2), 0&, 4
  
  ' show the rotated bitmap
  destPB.Refresh
  
End Sub

' Support routine

Private Function VarPtrArray(arr As Variant) As Long
  CopyMemory VarPtrArray, ByVal VarPtr(arr) + 8, 4
End Function


Submitted By : Nayan Patel  (Member Since : 5/26/2004 12:23:06 PM)

Job Description : He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting.
View all (893) submissions by this author  (Birth Date : 7/14/1981 )


Home   |  Comment   |  Contact Us   |  Privacy Policy   |  Terms & Conditions   |  BlogsZappySys

© 2008 BinaryWorld LLC. All rights reserved.