Jump to content

Display Color Palette using GDI+ (gif file only)


Malkey
 Share

Recommended Posts

This Script:-

- Choose and open a gif file to view its color palette;

- Hold left button down over square color sample on Color Palette GUI for tool tip. Tool tip displays color in 0xAARRGGBB format. If the AA part of that hexadecimal number is 00, then that color is transparent. So for that invisible color, what you see is the GUI (Graphical User Interface) color behind it.

- The gif file opened, displays at the bottom right corner of desktop.

This script does not open any other image file types apart from gif files. I tried and ran out of ideas.

I am thinking now that gdi32.dll functions may be better suited to play with color palettes. I don't intent to find out.

Other points of interest in script. (To my mind)

- Using _WinAPI_PtInRect() function on an array of rectangle structures to check if mouse is over a particular area. Goes well with _WinAPI_GetMousePos() which returns an x, y structure which can be used as a parameter for _WinAPI_PtInRect().

- The GDIPlus_BrushSetSolidColor() wrapper for the GdipSetSolidFillColor export function in gdiplus.dll.

Instead of creating and disposing of a brush, this wrapper/function changes the color of the one brush.

- The Color Palette GUI has double buffering. The gif display GUI does not. Therefore, gif display graphics is easily erased by moving off screen, or covering it with another window. The GDIPlus curse. The double buffering is not my creation.

The hex output of a gif file makes more sense to me now, having see its color palette.

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>

;ref http://www.autoitscript.com/forum/index.php?s=&showtopic=55443&view=findpost&p=420440
Opt('MustDeclareVars', 1)
Opt("GUIOnEventMode", 1)
Global $hGraphics, $iExit = 0, $aRect[257][2], $aData[267][6]

Local $File,$hImage1,$hImage,$iImageWidth,$iImageHeight,$hBitmap,$nSize,$ColPal
Local $hGraphic,$hGraphicGUI,$hBMPBuff,$hBrush

Local $iX = 1, $iY = 1, $iWidth = 23, $iHeight = 23
Local $File = FileOpenDialog("Choose Image File", @MyDocumentsDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)")
If $File <> "" Then
    _GDIPlus_Startup()
    $hImage1 = _GDIPlus_ImageLoadFromFile($File)
    $iImageWidth = _GDIPlus_ImageGetWidth($hImage1)
    $iImageHeight = _GDIPlus_ImageGetHeight($hImage1)
    $hBitmap = _GDIPlus_BitmapCreateFromFile($File) ; not necessary gif also woks with $hImage1
    $hImage = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iImageWidth, $iImageHeight, $GDIP_PXF32ARGB)
    ;ConsoleWrite("$hImage " & Hex($hImage) & @CRLF)

    $nSize = GDIPlus_GetImagePaletteSize($hImage)
    ;ConsoleWrite("$nSize " & $nSize & @CRLF)

    ;----- Color Palette Structure ---
    Global Const $tagColorPalette = "int Flags;int Count;int Entries[256]"
    Local $tColorPalette = DllStructCreate($tagColorPalette)
    ;DllStructSetData($tColorPalette, "Flags", 0x0005)
    ;DllStructSetData($tColorPalette, "Count", 256)
    ;-----> End of Color Palette Structure ---
    
    ;ConsoleWrite("$tColorPalette,Flags Before  = " & Hex(DllStructGetData($tColorPalette, "Flags")) & @CRLF)
    ;ConsoleWrite("$tColorPalette,Count Before = " & Hex(DllStructGetData($tColorPalette, "Count")) & @CRLF)
    $ColPal = GDIPlus_GetImagePalette($hImage, $tColorPalette, $nSize)
    ;ConsoleWrite("$tColorPalette,Flags After  = " & Hex(DllStructGetData($tColorPalette, "Flags")) & @CRLF)
    ;ConsoleWrite("$tColorPalette,Count After  = " & Hex(DllStructGetData($tColorPalette, "Count")) & @CRLF)
    
    ;Write colors in palette to console
    ;For $x = 1 To 5  ; 256
    ;   ConsoleWrite("Entries[" & $x & "] = " & Hex(DllStructGetData($tColorPalette, 3, $x)) & @CRLF)
    ;Next
    ;ConsoleWrite("=======" & @CRLF)

    Global $hGui = GUICreate($File, $iImageWidth, $iImageHeight, @DesktopWidth - $iImageWidth - 20, @DesktopHeight - $iImageHeight - 60)
    GUISetOnEvent($GUI_EVENT_CLOSE, "Quit")
    GUISetState()
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGui)
    _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)

    Global $hGuiPal = GUICreate("Color Palette", 400, 400, 10, 10)
    $aRect[0][0] = _WinAPI_GetWindowRect($hGuiPal) ; GUI rect struct
    GUISetOnEvent($GUI_EVENT_CLOSE, "Quit")
    GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "MouseDwn")
    GUISetOnEvent($GUI_EVENT_PRIMARYUP, "PrimMouseUp")
    GUISetState()
    
    ; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
    $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGuiPal)
    $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics(400, 400, $hGraphicGUI)
    $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
    ;End Double Buffer add-in 1 of 3
    
    $hBrush = _GDIPlus_BrushCreateSolid(0xffffffff) ;Initialize Brush
    For $x = 1 To 256
        $hBrush = GDIPlus_BrushSetSolidColor($hBrush, "0x" & Hex(DllStructGetData($tColorPalette, 3, $x)))
        _GDIPlus_GraphicsFillRect($hGraphics, $iX, $iY, $iWidth, $iHeight, $hBrush)
        $aRect[$x][0] = CreateRectStruct($iX, $iY, $iX + $iWidth, $iY + $iHeight)
        $aRect[$x][1] = "0x" & Hex(DllStructGetData($tColorPalette, 3, $x)) ; For ToolTip
        $iX += 25
        If $iX >= (16 * 25) Then
            $iY += 25
            $iX = 1
        EndIf
    Next
    ; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
    GUIRegisterMsg(0xF, "MY_PAINT")
    _WinAPI_RedrawWindow($hGuiPal, 0, 0, 2);$RDW_INTERNALPAINT = 0x0002 from WindowsConstants.au3
    ;End Double Buffer add-in 2 of 3
    While $iExit = 0
        Sleep(10)
    WEnd

    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _GDIPlus_ImageDispose($hImage1)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    _WinAPI_DeleteObject($hBMPBuff)
EndIf
Exit

;GdipGetImagePaletteSize(GpImage *image, INT *size)
; http://msdn.microsoft.com/en-us/library/ms535385(VS.85).aspx
;
Func GDIPlus_GetImagePaletteSize($hImage)
    Local $aResult, $res
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePaletteSize", "hwnd", $hImage, "int*", 0)
    _WinAPI_Check("GDIPlus_GetImagePaletteSize ", $aResult[0] <> 0, 3, True)
    ;ConsoleWrite("GDIPlus_GetImagePaletteSize" & @CRLF)
    ;For $x = 0 To UBound($aResult) - 1
    ;   ConsoleWrite("$aResult[" & $x & "] = " & $aResult[$x] & @CRLF)
    ;Next
    ;ConsoleWrite("=============" & @CRLF)
    Return $aResult[2]
EndFunc   ;==>GDIPlus_GetImagePaletteSize

;=========GDIPlus_GetImagePalette =============
;Parameters:
;$hImage       - [in] Handle to Image Object
;$ColorPalette - [out] Pointer to a ColorPalette structure that receives the palette.
;$Size         - [in] Integer that specifies the size, in bytes, of the palette.
;              - Call GdipGetImagePaletteSize function to determine the size.
;  ---------------------------------------------
;ColorPalette Structure - The ColorPalette structure defines an array of colors that make up a color palette.
;                         The colors are 32-bit ARGB colors.
;Syntax -  typedef struct {UINT Flags; UINT Count; ARGB Entries[1] } ColorPalette;
;Members -
;    Flags - Combination of flags from the PaletteFlags enumeration.
;          - PaletteFlagsHasAlpha = 0x0001,  - Indicates that one or more of the palette entries contains
;                                               alpha (transparency) information.
;          - PaletteFlagsGrayScale = 0x0002, - Indicates that the palette contains only grayscale entries.
;          - PaletteFlagsHalftone = 0x0004,  - Indicates that the palette is the Microsoft Windows halftone palette.
;    Count   - Number of elements in the Entries array.
;    Entries - Array of ARGB colors.
; GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
; Ref - http://msdn.microsoft.com/en-us/library/ms535384(VS.85).aspx
;
Func GDIPlus_GetImagePalette($hImage, ByRef $ColorPalette, $Size)
    Local $aResult
    
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetImagePalette", "hwnd", $hImage, _
            "ptr", DllStructGetPtr($ColorPalette), "int", $Size)
    ;ConsoleWrite("GDIPlus_GetImagePalette" & @CRLF)
    ;For $x = 0 To UBound($aResult) - 1
    ;   ConsoleWrite("$aResult[" & $x & "] = " & $aResult[$x] & @CRLF)
    ;Next
    ;ConsoleWrite("=============" & @CRLF)
    _WinAPI_Check("GDIPlus_GetImagePalette ", $aResult[0] <> 0, 3, True)
    Return $aResult[2]
EndFunc   ;==>GDIPlus_GetImagePalette

Func MouseDwn()
    $aRect[0][0] = _WinAPI_GetWindowRect($hGuiPal); Update $hGuiPal GUI Rect struct
    Local $tPoint = _WinAPI_GetMousePos()   ; Desktop coordinates
    If _WinAPI_PtInRect($aRect[0][0], $tPoint) Then ; Check if mouse is over $hGuiPal GUI
        Do
            $tPoint = _WinAPI_GetMousePos(True, $hGuiPal); GUI coordinates
            For $x = 1 To 256
                If _WinAPI_PtInRect($aRect[$x][0], $tPoint) Then 
                    TtipColor($x)
                EndIf
            Next
        Until $GUI_EVENT_PRIMARYUP
        
    EndIf
EndFunc   ;==>MouseDwn

Func PrimMouseUp()
    ToolTip("")
EndFunc   ;==>PrimMouseUp

; TtColXY() Shows Tooltip With Colour, X & Y position of Cursor
Func TtipColor($x)
    Local $aPos,$sColor,$iPosX,$iPosY
    $aPos = MouseGetPos()
    $sColor = "0x" & Hex(PixelGetColor($aPos[0], $aPos[1]), 6)
    $iPosX = ($aPos[0] - 100) * ($aPos[0] > @DesktopWidth * 0.90) + ($aPos[0] <= @DesktopWidth * 0.90) * ($aPos[0] + 3)
    $iPosY = ($aPos[1] - 30) * ($aPos[1] > @DesktopHeight * 0.96) + ($aPos[1] <= @DesktopHeight * 0.96) * ($aPos[1] + 3)
    ToolTip("  Number: " & $x & @CRLF & "Color is: " & $aRect[$x][1], $iPosX, $iPosY)
    Return
EndFunc   ;==>TtColXY

Func CreateRectStruct($iLeft, $iTop, $iRight, $iBottom)
    Local $tRect

    $tRect = DllStructCreate("int Left;int Top;int Right;int Bottom")
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)
    Return $tRect
EndFunc   ;==>CreateRectStruct

Func Quit()
    $iExit = 1
EndFunc   ;==>Quit

;===== GDIPlus_BrushSetSolidColor ======
; Description : Sets a color of an existing brush
; GdipSetSolidFillColor(GpSolidFill *brush, ARGB color)
;Ref http://msdn.microsoft.com/en-us/library/ms534051(VS.85).aspx
Func GDIPlus_BrushSetSolidColor($hBrush, $iARGB = 0xFF000000)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetSolidFillColor", "hwnd", $hBrush, "int", $iARGB)
    If @error Then Return SetError(@error, @extended, 0)
    ;For $x = 0 To UBound($aResult) - 1
    ;   ConsoleWrite("$aResult[" & $x & "] = " & $aResult[$x] & @CRLF)
    ;Next
    Return SetError($aResult[0], 0, $aResult[1])
EndFunc   ;==>GDIPlus_BrushSetSolidColor

;Func to redraw the BMP on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    ; Check, if the GUI with the Graphic should be repainted
    If $hWnd = $hGuiPal Then
        $aRect[0][0] = _WinAPI_GetWindowRect($hGuiPal)
        _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    EndIf
EndFunc   ;==>MY_PAINT ;End Double Buffer add-in 3 of 3

This may help someone, somehow.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...