# Visual Basic > Visual Basic 6 and Earlier >  [RESOLVED] Use GDI+ to get Photo Orientation and/or Rotate

## k_zeon

i am using the following to grab a thumbnail from a photo.



```
   Dim token As Long
    token = InitGDIPlus
    PicBox.Picture = modGDIPlusResize.LoadPictureGDIPlus(Filename, Width, Height, vbWhite, True) 
    FreeGDIPlus token
```



```
Public Function LoadPictureGDIPlus(PicFile As String, Optional Width As Long = -1, Optional Height As Long = -1, Optional ByVal BackColor As Long = vbWhite, Optional RetainRatio As Boolean = False) As IPicture
    Dim hDC As Long
    Dim hBitmap As Long
    Dim img As Long

    ' Load the image
    If GdipLoadImageFromFile(StrPtr(PicFile), img) <> 0 Then
        'err.Raise 999, "GDI+ Module", "Error loading picture " & PicFile
        'err.Clear
        ' NotGoodPicture = True
        Exit Function
    End If

    ' Calculate picture's width and height if not specified
    If Width = -1 Or Height = -1 Then
        GdipGetImageWidth img, Width
        GdipGetImageHeight img, Height
    End If

    ' Initialise the hDC
    InitDC hDC, hBitmap, BackColor, Width, Height

    ' Resize the picture
    gdipResize img, hDC, Width, Height, RetainRatio
    GdipDisposeImage img

    ' Get the bitmap back
    GetBitmap hDC, hBitmap

    ' Create the picture
    Set LoadPictureGDIPlus = CreatePicture(hBitmap)
End Function
```


How would i add to the code above to return an image based on angle of degree  ie  0deg  270deg  etc

I would like to add another option to the function ie  Optional Degree As integer= 0


tks

----------


## Brenker

I don't know how do you establish the photo's orientation reference "index".  Some people resort to ExifTool, for example.  I always read through the file by myself, as reading the Image File Directory, or IFD structure is not difficult at all.  If "ID" of the IFD being 274, then it is the photo's orientation tag.  Its index reference value can be from 1 to 8.



```
If the "index" value, say mIndex > 1, then you just adjust your existing hImg:

Select Case mIndex
        Case 2      '[Top, Right]
            GdipImageRotateFlip hImg, RotateNoneFlipX
        Case 3      '[Bottom, Right]
            GdipImageRotateFlip hImg, Rotate180FlipNone
        Case 4      '[Bottom, Left]
            GdipImageRotateFlip hImg, Rotate180FlipX
        Case 5      '[Left, Top]
            GdipImageRotateFlip hImg, Rotate270FlipY
        Case 6      '[Right, Top]
            GdipImageRotateFlip hImg, Rotate90FlipNone
        Case 7      '[Right, Bottom]
            GdipImageRotateFlip hImg, Rotate90FlipY
        Case 8      '[Left, Bottom]
            GdipImageRotateFlip hImg, Rotate270FlipNone
    End Select
```

N.B. The above might not always work, e.g. you already manually adjusted the orientation of the image before, or the EXIF data in file had been removed or damaged.

----------


## Brenker

Additional info for reference:

GDIplus has PropertyTagOrientation tag which has 8 settings from 1 to 8, corresponding to indices from 1 to 8 in my above posting.

----------


## wqweto

Here is how to get PropertyTagOrientation by filename.



```
Option Explicit

Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal sFileName As Long, hImage As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal Image As Long) As Long
Private Declare Function GdipGetPropertyItemSize Lib "gdiplus" (ByVal hImage As Long, ByVal lPropId As Long, lSize As Long) As Long
Private Declare Function GdipGetPropertyItem Lib "gdiplus" (ByVal hImage As Long, ByVal lPropId As Long, ByVal lPropSize As Long, uBuffer As Any) As Long

Public Function GetImagePropertyTagOrientation(sFileName As String) As Long
    Const PropertyTagOrientation As Long = &H112
    Dim hImage          As Long
    Dim lSize           As Long
    Dim aProp()         As Long
   
    If GdipLoadImageFromFile(StrPtr(sFileName), hImage) <> 0 Then
        GoTo QH
    End If
    If GdipGetPropertyItemSize(hImage, PropertyTagOrientation, lSize) <> 0 Then
        GoTo QH
    End If
    ReDim aProp(0 To lSize \ 4) As Long
    If GdipGetPropertyItem(hImage, PropertyTagOrientation, lSize, aProp(0)) <> 0 Then
        GoTo QH
    End If
    '--- for PropertyTagOrientation the returned PropertyItem.value in aProp(3) should point to actual value in aProp(4)
    If aProp(3) = VarPtr(aProp(4)) Then
        GetImagePropertyTagOrientation = aProp(4)
    End If
QH:
    If hImage <> 0 Then
        Call GdipDisposeImage(hImage)
    End If
End Function
```

Note that using this procedure might fully load your image (i.e. allocate memory and decompress it) so test performance before using in production or you might want to refactor it to accept an *hImage* as a parameter.

cheers,
</wqw>

----------


## k_zeon

tks for your replies, i have used shell namespace to get the orientation, but what i need now is the extra code to add to my function to rotate the image from centre
based on the orientation.

i tried a few options last night but they did not work.
i was thinking of adding a new function that would rotate before sending this back to the function.

somthing like



```
Private Sub Draw()
    Dim iWidth As Long, iHeight As Long
    
    GdipRotateWorldTransform Graphics, hsclAnle.Value, 1
    GdipTranslateWorldTransform Graphics, picOut.ScaleWidth / 2, picOut.ScaleHeight / 2, 1
    GdipGraphicsClear Graphics, &HFFFFFFFF
    GdipGetImageWidth Bitmap, iWidth
    GdipGetImageHeight Bitmap, iHeight
    GdipDrawImageRect Graphics, Bitmap, -hsclXPos.Value, -vsclYPos.Value, iWidth, iHeight
    GdipResetWorldTransform Graphics
    GdipDrawEllipse Graphics, Pen, picOut.ScaleWidth / 2, picOut.ScaleHeight / 2, 3, 3
    picOut.Refresh
End Sub
```

I thnik this was from an example by Lavolpe, so will try tonight to see if i can make this work

or if anyone can advise the needed code

tks

----------


## Brenker

As I see it,  you only need to do 2 things:

(1) Separately establish the value of "mIndex" first, e.g. by using the function duly supplied by wqweto above, or some other subroutine you already have.

(2) Before your existing code line 



```
    If Width = -1 Or Height = -1 Then
```

add my code block in Posting #2, i.e. 



```
Remarks: "hImg" below is actually your "Img".
 
Select Case mIndex
        Case 2      '[Top, Right]
            GdipImageRotateFlip hImg, RotateNoneFlipX
        Case 3      '[Bottom, Right]
            GdipImageRotateFlip hImg, Rotate180FlipNone
        Case 4      '[Bottom, Left]
            GdipImageRotateFlip hImg, Rotate180FlipX
        Case 5      '[Left, Top]
            GdipImageRotateFlip hImg, Rotate270FlipY
        Case 6      '[Right, Top]
            GdipImageRotateFlip hImg, Rotate90FlipNone
        Case 7      '[Right, Bottom]
            GdipImageRotateFlip hImg, Rotate90FlipY
        Case 8      '[Left, Bottom]
            GdipImageRotateFlip hImg, Rotate270FlipNone
 End Select
```

----------


## georgekar

Take a look here https://github.com/M2000Interpreter/...n/ExifRead.cls
Read at most 2000 bytes

I use it like this:


```
Public Sub CheckOrientation(a As cDIBSection, f As String)
    If LCase(ExtractType(f, (0))) = "jpg" Then
        Dim qw As New ExifRead
        qw.Load f
        Select Case qw.Tag(Orientation)
        Case 3
          RotateDib180 a
        Case 8
          RotateDib90 a
        Case 6
          RotateDib270 a
        End Select
    End If
End Sub
```

----------


## k_zeon

> As I see it,  you only need to do 2 things:
> 
> (1) Separately establish the value of "mIndex" first, e.g. by using the function duly supplied by wqweto above, or some other subroutine you already have.
> 
> (2) Before your existing code line 
> 
> 
> 
> ```
> ...


many thanks Brenker. works like a charm. did have to find a few declares and the GdipImageRotateFlip   declaration

is there a complete GDI+ module anywhere that will have all declares, functions etc

tks

----------


## Brenker

You already have all declarations etc which pertain to your own code in Posting #1.  To obtain the "mIndex" value, wqweto supplied a function and the  constant for PropertyTagOrientation tag etc.   Here are some Types pertaining to the rotation:

Private Declare Function GdipImageRotateFlip Lib "gdiplus" (ByVal image As Long, _
    ByVal rfType As Long) As GpStatus

Private Enum RotateFlipType
    RotateNoneFlipNone = 0
    Rotate90FlipNone = 1
    Rotate180FlipNone = 2
    Rotate270FlipNone = 3

    RotateNoneFlipX = 4
    Rotate90FlipX = 5
    Rotate180FlipX = 6
    Rotate270FlipX = 7

    RotateNoneFlipY = Rotate180FlipX
    Rotate90FlipY = Rotate270FlipX
    Rotate180FlipY = RotateNoneFlipX
    Rotate270FlipY = Rotate90FlipX

    RotateNoneFlipXY = Rotate180FlipNone
    Rotate90FlipXY = Rotate270FlipNone
    Rotate180FlipXY = RotateNoneFlipNone
    Rotate270FlipXY = Rotate90FlipNone
End Enum

You asked "is there a complete GDI+ module anywhere that will have all declares, functions etc".  I'd come across a few such BAS and similar documentation; I found them too bulky to keep for practical purposes.

----------


## k_zeon

> You already have all declarations etc which pertain to your own code in Posting #1.  To obtain the "mIndex" value, wqweto supplied a function and the  constant for PropertyTagOrientation tag etc.   Here are some Types pertaining to the rotation:
> 
> Private Declare Function GdipImageRotateFlip Lib "gdiplus" (ByVal image As Long, _
>     ByVal rfType As Long) As GpStatus
> 
> Private Enum RotateFlipType
>     RotateNoneFlipNone = 0
>     Rotate90FlipNone = 1
>     Rotate180FlipNone = 2
> ...


yes, thats exactly what i had to find as i did not have this in my existing module.
All works perfectly. tks

----------

