Sign in to follow this  
Followers 0
rover

GDI+ Image functions: DPI, Pixelformat etc.

12 posts in this topic

#1 ·  Posted (edited)

DPI, Pixelformat and other image info from GDI+ API.

I needed DPI and pixel format info for a script,

so I translated a few of the less exciting useable GDI functions.

maybe someone else can use them, or not.

_GDIPlus_ImageGetHorizontalResolution() DPI - pixels per inch

_GDIPlus_ImageGetVerticalResolution() DPI - pixels per inch

_GDIPlus_ImageGetType() Bitmap (BMP,PNG,GIF,JPEG,TIFF,ICO,EXIF), Metafile (EMF, WMF) or Unidentified

_GDIPlus_ImageGetFlags() color space, alpha and other properties

_GDIPlus_ImageGetPixelFormat() Bits per pixel, RGB format, alpha channels

_GDIPlus_ImageGetRawFormat() image file format

Edit: Uploaded updated and formatted UDFs with examples: see attachment

Edit: functions now in GDIPlus.au3 include as of AutoIt version 3.2.13.8 (4th October, 2008) (Beta)

Edit: replaced attachment with updated examples, in beta now anyway

Example script

#include <GDIPlus.au3>
#include <Array.au3>

Opt('MustDeclareVars', 1)

; GDI+ Image File Format Constants
; Globally Unique Identifier (GUID)
Global Const $GDIP_IMAGEFORMAT_UNDEFINED = "{B96B3CA9-0728-11D3-9D7B-0000F81EF32E}" ; Windows GDI+ is unable to determine the format.
Global Const $GDIP_IMAGEFORMAT_MEMORYBMP = "{B96B3CAA-0728-11D3-9D7B-0000F81EF32E}" ; Image was constructed from a memory bitmap.
Global Const $GDIP_IMAGEFORMAT_BMP = "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}" ; Microsoft Windowsbitmap (BMP) format.
Global Const $GDIP_IMAGEFORMAT_EMF = "{B96B3CAC-0728-11D3-9D7B-0000F81EF32E}" ; Enhanced Metafile (EMF) format.
Global Const $GDIP_IMAGEFORMAT_WMF = "{B96B3CAD-0728-11D3-9D7B-0000F81EF32E}" ; Windows Metafile Format (WMF) format.
Global Const $GDIP_IMAGEFORMAT_JPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}" ; JPEG format.
Global Const $GDIP_IMAGEFORMAT_PNG = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}" ; Portable Network Graphics (PNG) format.
Global Const $GDIP_IMAGEFORMAT_GIF = "{B96B3CB0-0728-11D3-9D7B-0000F81EF32E}" ; Graphics Interchange Format (GIF) format.
Global Const $GDIP_IMAGEFORMAT_TIFF = "{B96B3CB1-0728-11D3-9D7B-0000F81EF32E}" ; Tagged Image File Format (TIFF) format.
Global Const $GDIP_IMAGEFORMAT_EXIF = "{B96B3CB2-0728-11D3-9D7B-0000F81EF32E}" ; Exif (Exchangeable Image File) format.
Global Const $GDIP_IMAGEFORMAT_ICON = "{B96B3CB5-0728-11D3-9D7B-0000F81EF32E}" ; Icon format.

; GdipGetImageType constants
Global Const $GDIP_IMAGETYPE_UNKNOWN = 0
Global Const $GDIP_IMAGETYPE_BITMAP = 1
Global Const $GDIP_IMAGETYPE_METAFILE = 2

; GdipGetImageFlags constants
;The ImageFlags enumeration specifies the attributes of the pixel data contained in an image.
Global Const $GDIP_IMAGEFLAGS_NONE = 0x0 ; no format information.
Global Const $GDIP_IMAGEFLAGS_SCALABLE = 0x0001 ; image can be scaled.
Global Const $GDIP_IMAGEFLAGS_HASALPHA = 0x0002 ; pixel data contains alpha values.
Global Const $GDIP_IMAGEFLAGS_HASTRANSLUCENT = 0x0004 ; pixel data has alpha values other than 0 (transparent) and 255 (opaque).
Global Const $GDIP_IMAGEFLAGS_PARTIALLYSCALABLE = 0x0008 ; pixel data is partially scalable with some limitations.
;color space definition
Global Const $GDIP_IMAGEFLAGS_COLORSPACERGB = 0x0010 ; image is stored using an RGB color space.
Global Const $GDIP_IMAGEFLAGS_COLORSPACECMYK = 0x0020 ; image is stored using a CMYK color space.
Global Const $GDIP_IMAGEFLAGS_COLORSPACEGRAY = 0x0040 ; image is a grayscale image.
Global Const $GDIP_IMAGEFLAGS_COLORSPACEYCBCR = 0x0080 ; image is stored using a YCBCR color space.
Global Const $GDIP_IMAGEFLAGS_COLORSPACEYCCK = 0x0100 ; image is stored using a YCCK color space.
;image size info
Global Const $GDIP_IMAGEFLAGS_HASREALDPI = 0x1000 ; dots per inch information is stored in the image.
Global Const $GDIP_IMAGEFLAGS_HASREALPIXELSIZE = 0x2000 ; pixel size is stored in the image.
Global Const $GDIP_IMAGEFLAGS_READONLY = 0x00010000 ; pixel data is read-only.
Global Const $GDIP_IMAGEFLAGS_CACHING = 0x00020000 ; pixel data can be cached for faster access.

; Example
Global $aImageInfo = _GDI_ImageInfoExample()
_ArrayDisplay($aImageInfo, "GDI+ image file info functions example", Default, Default, "*")


Func _GDI_ImageInfoExample()
    Local $aArray[1][7], $sFileDialogtitle, $sPath, $aFileImage, $himage, $sImageType
    Local $iDPIh, $iDPIv, $sPixel, $sFormat, $iFlags
    ;$sPath = @MyDocumentsDir & "\My Pictures"
    $sFileDialogtitle = "Select a folder of these image file formats: JPG-PNG-BMP-GIF-TIF-WMF-EMF-ICO"
    $sPath = FileSelectFolder($sFileDialogtitle, "", 6, "::{450D8FBA-AD25-11D0-98A8-0800361B1103}")
    If @error Then Exit
    $aFileImage = __FileListToArray($sPath, "*.jpg;*.png;*.bmp;*.gif;*.tif;*.wmf;*.emf;*.ico")
    If @error Or Not IsArray($aFileImage) Then
        MsgBox(0, "", "No Files\Folders Found.")
        Exit
    EndIf
    ReDim $aArray[$aFileImage[0] + 1][7]

    ; Initialize GDI+ library
    _GDIPlus_Startup()

    ConsoleWrite(@CRLF)
    For $i = 1 To $aFileImage[0]
        If Not FileExists($aFileImage[$i]) Then
            ConsoleWrite("! File does not exist: " & $aFileImage & @CRLF)
            ContinueLoop
        EndIf
        $himage = _GDIPlus_ImageLoadFromFile($aFileImage[$i])
        ;ConsoleWrite('-> Handle = ' & $himage & @crlf)

        $sImageType = _GDIPlus_ImageGetType($himage)
        Switch $sImageType
            Case $GDIP_IMAGETYPE_UNKNOWN
                $sImageType = "Unrecognized bitmap format or not image file"
                ConsoleWrite("! Problem with this imagefile: " & $aFileImage[$i] & @CRLF & @CRLF)
            Case $GDIP_IMAGETYPE_BITMAP
                $sImageType = "Bitmap"
            Case $GDIP_IMAGETYPE_METAFILE
                $sImageType = "Metafile"
        EndSwitch
        
        $iFlags = _GDIPlus_ImageGetFlags($himage)
        $sFormat = _GDIPlus_ImageGetRawFormat($himage)
        $sPixel = _GDIPlus_ImageGetPixelFormat($himage)
        $iDPIh = _GDIPlus_ImageGetHorizontalResolution($himage)
        $iDPIv = _GDIPlus_ImageGetVerticalResolution($himage)
        
        _GDIPlus_ImageDispose($himage)
        
        $aArray[$i - 1][0] = "File:  " & $aFileImage[$i]
        $aArray[$i - 1][1] = "IsImage:  " & $sImageType
        $aArray[$i - 1][2] = "RawFormat:  " & $sFormat
        $aArray[$i - 1][3] = "PixelFormat:  " & $sPixel
        $aArray[$i - 1][4] = "HorizontalRes-DPI:  " & $iDPIh
        $aArray[$i - 1][5] = "VerticalRes-DPI:  " & $iDPIv
        $aArray[$i - 1][6] = "Flags:  " & $iFlags
        
        ConsoleWrite("+> File: " & @TAB & @TAB & @TAB & @TAB & $aFileImage[$i] & @CRLF)
        ConsoleWrite("+> IsImage: " & @TAB & @TAB & @TAB & @TAB & $sImageType & @CRLF)
        ConsoleWrite("+> ImageGetFlags: " & @TAB & @TAB & @TAB & $iFlags & @CRLF)
        ConsoleWrite("+> GdipImageGetRawFormat: " & @TAB & @TAB & $sFormat & @CRLF)
        ConsoleWrite("+> GdipImageGetPixelFormat: " & @TAB & @TAB & $sPixel & @CRLF)
        ConsoleWrite("+> GdipImageGetHorizontalResolution: " & @TAB & $iDPIh & @CRLF)
        ConsoleWrite("+> GdipImageGetVerticalResolution: " & @TAB & $iDPIv & @CRLF & @CRLF)
    Next
    Return $aArray
EndFunc   ;==>_GDI_ImageInfoExample

Func __FileListToArray($sPath, $sFilter = "*") ; modified _FileListToArray() from File.au3
    ; return full path and filename in array
    Local $hSearch, $sFile, $asFileList[1], $aSearch
    If Not FileExists($sPath) Then Return SetError(1, 1, "")
    $aSearch = StringSplit($sFilter, ";")
    If Not IsArray($aSearch) Then Return SetError(1, 1, "")
    If (StringMid($sPath, StringLen($sPath), 1) <> "\") Then $sPath &= "\"
    For $i = 1 To $aSearch[0]
        $hSearch = FileFindFirstFile($sPath & $aSearch[$i])
        Switch $hSearch
            Case - 1
                Select
                    Case $i <> $aSearch[0]
                        ContinueLoop
                    Case $i = $aSearch[0] And UBound($asFileList) = 1
                        Return SetError(4, 4, "")
                    Case $i = $aSearch[0] And UBound($asFileList) > 1
                        Return $asFileList
                    Case Else
                        Return SetError(4, 4, "")
                EndSelect
            Case Else
        EndSwitch
        
        While 1
            $sFile = FileFindNextFile($hSearch)
            If @error Then
                SetError(0)
                ExitLoop
            EndIf
            If StringInStr(FileGetAttrib($sPath & $sFile), "D") <> 0 Then ContinueLoop
            ReDim $asFileList[UBound($asFileList) + 1]
            $asFileList[0] = $asFileList[0] + 1
            $asFileList[UBound($asFileList) - 1] = $sPath & $sFile
        WEnd
        FileClose($hSearch)
    Next
    Return $asFileList
EndFunc   ;==>__FileListToArray

Func OnAutoItExit()
    ; Shut down GDI+ library
    If $ghGDIPDll <> 0 Then _GDIPlus_Shutdown()
EndFunc   ;==>OnAutoItExit

; /Example



Func _GDIPlus_ImageGetHorizontalResolution($himage)
    ; DPI - Pixels per inch
    Local $aResult, $iError = 0
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImageHorizontalResolution", _
            "hwnd", $himage, "float*", 0)
    $iError = @error
    If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 0, 0)
    Return SetError($aResult[0], 0, Round($aResult[2]))
EndFunc   ;==>_GDIPlus_ImageGetHorizontalResolution

Func _GDIPlus_ImageGetVerticalResolution($himage)
    ; DPI - Pixels per inch
    Local $aResult, $iError = 0
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImageVerticalResolution", _
            "hwnd", $himage, "float*", 0)
    $iError = @error
    If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 0, 0)
    Return SetError($aResult[0], 0, Round($aResult[2]))
EndFunc   ;==>_GDIPlus_ImageGetVerticalResolution

Func _GDIPlus_ImageGetType($himage)
    ; Non bitmap files or proprietary bitmap formats not identified as bitmaps by GDI+ = 0
    ; IsBitmap (BMP,PNG,GIF,JPEG,TIFF,ICO,EXIF) = 1
    ; IsMetafile (EMF, WMF) = 2
    ; error = -1
    Local $aResult, $iError = 0
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImageType", "hwnd", $himage, "int*", 0)
    $iError = @error
    If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 0, -1)
    Return SetError($aResult[0], 0, $aResult[2])
EndFunc   ;==>_GDIPlus_ImageGetType

Func _GDIPlus_ImageGetFlags($himage)
    ; returns string of properties separated by delimiter "|"
    Local $aResult, $sFlag, $iError = 0, $aImageFlags[13][2] = _
            [["Pixel data Cacheable", $GDIP_IMAGEFLAGS_CACHING], _
            ["Pixel data read-only", $GDIP_IMAGEFLAGS_READONLY], _
            ["Pixel size in image", $GDIP_IMAGEFLAGS_HASREALPIXELSIZE], _
            ["DPI info in image", $GDIP_IMAGEFLAGS_HASREALDPI], _
            ["YCCK color space", $GDIP_IMAGEFLAGS_COLORSPACEYCCK], _
            ["YCBCR color space", $GDIP_IMAGEFLAGS_COLORSPACEYCBCR], _
            ["Grayscale image", $GDIP_IMAGEFLAGS_COLORSPACEGRAY], _
            ["CMYK color space", $GDIP_IMAGEFLAGS_COLORSPACECMYK], _
            ["RGB color space", $GDIP_IMAGEFLAGS_COLORSPACERGB], _
            ["Partially scalable", $GDIP_IMAGEFLAGS_PARTIALLYSCALABLE], _
            ["Alpha values other than 0 (transparent) and 255 (opaque)", $GDIP_IMAGEFLAGS_HASTRANSLUCENT], _
            ["Alpha values", $GDIP_IMAGEFLAGS_HASALPHA], _
            ["Scalable", $GDIP_IMAGEFLAGS_SCALABLE]]
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImageFlags", "hwnd", $himage, "long*", 0)
    $iError = @error
    If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 1, "")
    If $aResult[2] = $GDIP_IMAGEFLAGS_NONE Then Return SetError($aResult[0], 2, "No format information")
    For $i = 0 To 12
        If BitAND($aResult[2], $aImageFlags[$i][1]) = $aImageFlags[$i][1] Then
            If StringLen($sFlag) Then $sFlag &= "|"
            $aResult[2] -= $aImageFlags[$i][1]
            $sFlag &= $aImageFlags[$i][0]
        EndIf
    Next
    Return SetError($aResult[0], 0, $sFlag)
EndFunc   ;==>_GDIPlus_ImageGetFlags

Func _GDIPlus_ImageGetPixelFormat($himage)
    ; using globally declared constants for ImagePixelFormat identification
    ; returns string identifier
    Local $aResult, $iError = 0
    Local $aPixelFormat[14][2] = _
            [["1 Bpp Indexed", $GDIP_PXF01INDEXED], _
            ["4 Bpp Indexed", $GDIP_PXF04INDEXED], _
            ["8 Bpp Indexed", $GDIP_PXF08INDEXED], _
            ["16 Bpp Grayscale", $GDIP_PXF16GRAYSCALE], _
            ["16 Bpp RGB 555", $GDIP_PXF16RGB555], _
            ["16 Bpp RGB 565", $GDIP_PXF16RGB565], _
            ["16 Bpp ARGB 1555", $GDIP_PXF16ARGB1555], _
            ["24 Bpp RGB", $GDIP_PXF24RGB], _
            ["32 Bpp RGB", $GDIP_PXF32RGB], _
            ["32 Bpp ARGB", $GDIP_PXF32ARGB], _
            ["32 Bpp PARGB", $GDIP_PXF32PARGB], _
            ["48 Bpp RGB", $GDIP_PXF48RGB], _
            ["64 Bpp ARGB", $GDIP_PXF64ARGB], _
            ["64 Bpp PARGB", $GDIP_PXF64PARGB]]
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePixelFormat", "hwnd", $himage, "int*", 0)
    $iError = @error
    If @error Or IsArray($aResult) = 0 Then Return SetError($iError, 1, "")
    For $i = 0 To 13
        If $aPixelFormat[$i][1] = $aResult[2] Then
            Return SetError($aResult[0], 0, $aPixelFormat[$i][0])
        EndIf
    Next
    Return SetError($aResult[0], 2, "")
EndFunc   ;==>_GDIPlus_ImageGetPixelFormat

Func _GDIPlus_ImageGetRawFormat($himage)
    ;Returns string image type identifier
    Local $aResult1, $aResult2, $tStruc, $iError = 0
    Local $aType[11][2] = _
            [["UNDEFINED", $GDIP_IMAGEFORMAT_UNDEFINED], _
            ["MEMORYBMP", $GDIP_IMAGEFORMAT_MEMORYBMP], _
            ["BMP", $GDIP_IMAGEFORMAT_BMP], _
            ["EMF", $GDIP_IMAGEFORMAT_EMF], _
            ["WMF", $GDIP_IMAGEFORMAT_WMF], _
            ["JPEG", $GDIP_IMAGEFORMAT_JPEG], _
            ["PNG", $GDIP_IMAGEFORMAT_PNG], _
            ["GIF", $GDIP_IMAGEFORMAT_GIF], _
            ["TIFF", $GDIP_IMAGEFORMAT_TIFF], _
            ["EXIF", $GDIP_IMAGEFORMAT_EXIF], _
            ["ICON", $GDIP_IMAGEFORMAT_ICON]]
    $tStruc = DllStructCreate("byte[16]")
    $iError = @error
    If @error Or (Not IsDllStruct($tStruc)) Then Return SetError($iError, 1, "")
    $aResult1 = DllCall($ghGDIPDll, "int", "GdipGetImageRawFormat", "hwnd", $himage, _
            "ptr", DllStructGetPtr($tStruc))
    $iError = @error
    If @error Or (Not IsArray($aResult1)) Or (Not IsPtr($aResult1[2])) Or _
            (Not $aResult1[2]) Then Return SetError($iError, 2, "")
    $aResult2 = DllCall("Ole32.dll", "int", "StringFromGUID2", "ptr", $aResult1[2], "wstr", "", "int", 40)
    $iError = @error
    If @error Or (Not IsArray($aResult2)) Or (Not $aResult2[2]) Then Return SetError($iError, 3, "")
    For $i = 0 To 10
        If $aType[$i][1] == $aResult2[2] Then Return SetError(0, 0, $aType[$i][0])
    Next
    Return SetError($aResult2[0], 4, "")
EndFunc   ;==>_GDIPlus_ImageGetRawFormat

_GDIPlus_ImageInfo_UDF.zip

Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Hi, good to see someone else poking around MSDN for GDI+ Image functions :P

I've been doing the same myself lately as I'd like to see more Image functions added AutoIt's GDI+ UDF.

Some I've submitted to trac as a request, some I haven't.

You should get the functions into standard UDF format and submit them to trac as a request to be added (if you haven't already).

Cheers

Edit:

so I translated a few of the less exciting useable GDI functions.

That's funny, I translated some less exciting useable GDI functions and it gave me the power to display/extract animated gifs and create/dislpay/extract multi-page tif files (turned out to be exciting for me anyways) :P Edited by smashly

Share this post


Link to post
Share on other sites

Hi, good to see someone else poking around MSDN for GDI+ Image functions :P

I've been doing the same myself lately as I'd like to see more Image functions added AutoIt's GDI+ UDF.

Some I've submitted to trac as a request, some I haven't.

You should get the functions into standard UDF format and submit them to trac as a request to be added (if you haven't already).

Cheers

Edit:

That's funny, I translated some less exciting useable GDI functions and it gave me the power to display/extract animated gifs and create/dislpay/extract multi-page tif files (turned out to be exciting for me anyways) :P

Please see item #4 located at: http://www.autoitscript.com/autoit3/udfs/UDF_Standards.htm


SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

@smashly

@Zedna

Thanks guys!

Hi, good to see someone else poking around MSDN for GDI+ Image functions :P

I've been doing the same myself lately as I'd like to see more Image functions added AutoIt's GDI+ UDF.

Some I've submitted to trac as a request, some I haven't.

You should get the functions into standard UDF format and submit them to trac as a request to be added (if you haven't already).

Cheers

It's more like 'getting lost' in the corridors of MSDN than poking around :P

though I only found useful GDI+ examples on non MS sites like:

http://www.com.it-berater.org/gdiplus/GdiPlus.htm

http://www.jose.it-berater.org/smfforum

and others

That's funny, I translated some less exciting useable GDI functions and it gave me the power to display/extract animated gifs and create/dislpay/extract multi-page tif files (turned out to be exciting for me anyways) :o

many of us don't have the skills to do the exciting graphics stuff,

but we do get the benefit of what others come up with. :D

I had a look at the animated GIF GDI+ UDF you posted, very nice!

Edit: link reminder, thanks Zedna

Animated Gif using GDI+, Drawing an animated gif on a layered window

@GaryFrost

@smashly

I've formatted the functions with some changes and have submitted the UDFs for evaluation

be seeing you...

Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Read it, as usual, sorry about that.

Looks like what I submitted in the wrong place is rejected.

I won't be resubmitting correctly, once is enough for me.

Cheers

smashly

not unlike book publishing, and many other things in life

submitting suggestions or UDFs has a high rejection rate,

but don't let that discourage you.

The rejection comes from posting in the wrong place,

maybe they will be rejected even if submitted properly.

it's still worth the exercise to post a finished UDF.

at minimum you can post the the completed formatted UDFs with examples

for others to find.

resubmit the UDFs using the template software and UDF guidelines and PM the zip

to Gary.

I've uploaded the zip I submitted of the formatted functions

attachment removed: see first post

good luck

rover

Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites

Thank you, Rover !!

I've added this stuff to my program so I could get the horizontal dpi (to make my code more dpi friendly)

and it works GREAT.

Now I can move on.

I spent hours and hours trying to find a simple way to get that DPI.

Finally, I stumbled on - or found somehow - your stuff... and it was the right stuff.

Share this post


Link to post
Share on other sites

Thank you, Rover !!

I've added this stuff to my program so I could get the horizontal dpi (to make my code more dpi friendly)

and it works GREAT.

Now I can move on.

I spent hours and hours trying to find a simple way to get that DPI.

Finally, I stumbled on - or found somehow - your stuff... and it was the right stuff.

Thanks Sycamore :P

I see fascists...

Share this post


Link to post
Share on other sites

A heads up for the examples in the v3.2.13.9 (beta) help file.

Three of the examples,

_GDIPlus_ImageGetFlags()

_GDIPlus_ImageGetPixelFormat()

_GDIPlus_ImageGetRawFormat()

save the image to a BMP file. Then example tries to load the same file name with a JPG extension.

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

A heads up for the examples in the v3.2.13.9 (beta) help file.

Three of the examples,

_GDIPlus_ImageGetFlags()

_GDIPlus_ImageGetPixelFormat()

_GDIPlus_ImageGetRawFormat()

save the image to a BMP file. Then example tries to load the same file name with a JPG extension.

Thanks Malkey :(

cut 'n' paste error when assembling the examples from other GDI+ help file examples :P

Edit: submitted changes to Trac. Ticket #617

Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0