No announcement yet.

Ghost Icons (GDI API)

  • Filter
  • Time
  • Show
Clear All
new posts

  • Ghost Icons (GDI API)

    (PB8 Windows XP)

    I recently had the need to be able to create a "ghost" icon, similiar to that which explorer creates to indicate a file or directory is hidden.

    After struggling to find anything on the internet I made a function. I have it working fine when the screen is set to 16-bit colour mode, but in 32-bit the icon mask seems to have a problem:

    Normal icon:

    Ghosted icon in 16-bit:

    Ghosted icon in 32-bit:

    I thought that perhaps someone with more knowledge of this sort of thing might know what the problem is. Also I am sure it would run faster if there is a way to get all the bits in one go rather than using GetPixel.

    Here is the function. It takes an HICON handle of the original icon, and returns a new HICON handle for the new icon:

    Function CreateGhostIcon(ByVal SourceIcon As Dword) As Dword
    Local MemoryDC_Source As Dword
    Local MemoryDC_Target As Dword
    Local MemoryDC_Mask As Dword
    Local MainDC As Dword
    Local NewIcon As Dword
    Local SourceBitmap As Bitmap
    Local OldBitmap_Source As Dword
    Local OldBitmap_Target As Dword
    Local OldBitmap_Mask As Dword
    Local SourceIconInfo As ICONINFO
    Local NewIconInfo As ICONINFO
    Local IconHeight As Long
    Local IconWidth As Long
    Local IconY As Long
    Local IconX As Long
    Local SourcePixel As Dword
    Local SourceMask As Dword
    Local ColourR As Byte
    Local ColourG As Byte
    Local ColourB As Byte
    Local ColourAverage As Byte
    MainDC = GetDC(0)
    MemoryDC_Source = CreateCompatibleDC(MainDC)
    MemoryDC_Target = CreateCompatibleDC(MainDC)
    MemoryDC_Mask = CreateCompatibleDC(MainDC)
    ReleaseDC 0, MainDC
    If GetIconInfo(SourceIcon,SourceIconInfo) <> 0 And GetObject(SourceIconInfo.hbmColor, Len(Bitmap),SourceBitmap) <> 0 Then
     IconHeight =  SourceIconInfo.yHotSpot * 2
     IconWidth =  SourceIconInfo.xHotSpot * 2
     NewIconInfo.hbmColor = CreateBitmap(IconWidth,IconHeight,SourceBitmap.bmPlanes,SourceBitmap.bmBitsPixel,ByVal 0)
     If NewIconInfo.hbmColor <> 0 Then
      OldBitmap_Source = SelectObject(MemoryDC_Source,SourceIconInfo.hbmColor )
      OldBitmap_Target = SelectObject(MemoryDC_Target,NewIconInfo.hbmColor)
      OldBitmap_Mask = SelectObject(MemoryDC_Mask,SourceIconInfo.hbmMask)
      For IconY = 0 To IconHeight -1
       For IconX = 0 To IconWidth -1 
        SourcePixel = GetPixel(MemoryDC_Source,IconX,IconY)
        SourceMask = GetPixel(MemoryDC_Mask,IconX,IconY)
        If SourceMask = 0 Then
         ' Retrieve and lighten the colours
         ColourR = (GetRValue(SourcePixel) + 255) \ 2
         ColourG = (GetGValue(SourcePixel) + 255) \ 2
         ColourB = (GetBValue(SourcePixel) + 255) \ 2
         ' Get the average colour value and use it to make the colours more similiar to each other (ie more grey)
         ColourAverage = (ColourR + ColourG + ColourB) \ 3
         ColourR = (ColourR + ColourAverage + ColourAverage) \ 3
         ColourG = (ColourG + ColourAverage + ColourAverage) \ 3
         ColourB = (ColourB + ColourAverage + ColourAverage) \ 3
         SetPixel MemoryDC_Target,IconX,IconY,RGB(ColourR,ColourG,ColourB)
        End If
      SelectObject MemoryDC_Source, OldBitmap_Source
      SelectObject MemoryDC_Target, OldBitmap_Target
      SelectObject MemoryDC_Mask, OldBitmap_Mask
      NewIconInfo.fIcon = %TRUE
      NewIconInfo.yHotSpot =  SourceIconInfo.yHotSpot
      NewIconInfo.xHotSpot =  SourceIconInfo.xHotSpot
      NewIconInfo.hbmMask = SourceIconInfo.hbmMask
      NewIcon = CreateIconIndirect(NewIconInfo)
      DeleteObject NewiconInfo.hbmColor
     End If
     DeleteObject SourceIconInfo.hbmColor
     DeleteObject SourceIconInfo.hbmMask
    End If
    ReleaseDC 0, MemoryDC_Source
    ReleaseDC 0, MemoryDC_Target
    ReleaseDC 0, MemoryDC_Mask
    Function = NewIcon
    End Function

  • #2
    I've used this for ages to create disabled owner drawn command buttons.
    might be something in there somewhere you can use.


      CreateDisabledBitmap ( _
        BYVAL hBitmap AS DWORD _
      ) AS  DWORD
      DIM bmInfo		AS BITMAP,_
          hbmOld		AS DWORD,_
          hbmShadow		AS DWORD,_
          hbmHighlight	AS DWORD,_
          hbmDisabled	AS DWORD,_
          hbrPat		AS DWORD,_
          hDc			AS DWORD,_
          hColorDC		AS DWORD,_
          hMonoDC		AS DWORD
         RGB_WHITE			AS LONG,_
         RGB_BLACK			AS LONG
     DIM PSDPxax			AS LONG   
      RGB_BTNFACE = GetSysColor(%COLOR_BTNFACE)   
      RGB_WHITE = RGB(255,255,255)
      RGB_BLACK = RGB(1,1,1)
      PSDPxax = &H00B8074A
      hbmDisabled = 0
      hDc = GetDC(0)
      hMonoDc = CreateCompatibleDC(hDc)
      hColorDc = CreateCompatibleDc(hDc)
      IF ((hMonoDc = 0) + (hColorDc = 0)) THEN
        FUNCTION = 0
      END IF
      GetObject hBitmap,SIZEOF(bmInfo),bmInfo
      hbmShadow = CreateBitmap(bmInfo.bmWidth,bmInfo.bmHeight,1,1,BYVAL 0)
      hbmHighlight =  CreateBitmap(bmInfo.bmWidth,bmInfo.bmHeight,1,1,BYVAL 0)
      hbmDisabled = CreateCompatibleBitmap(hDc,bmInfo.bmWidth,bmInfo.bmHeight)
      hbmOld = SelectObject(hColorDc,hBitmap)
      SetBkColor hColorDc,GetPixel(hColorDc,2,2)
      'Create shadow bitmap
      hbmShadow = SelectObject(hMonoDc,hbmShadow)
      PatBlt hMonoDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,%WHITENESS
      BitBlt hMonoDc,0,0,bmInfo.bmWidth - 1,bmInfo.bmHeight - 1,hColorDc,1,1,%SRCCOPY
      BitBlt hMonoDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,hColorDc,0,0,%MERGEPAINT
      hbmShadow = SelectObject(hMonoDc,hbmShadow)
      'Create highlight bitmap
      hbmHighlight = SelectObject(hMonoDc,hbmHighlight)
      BitBlt hMonoDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,hColorDc,0,0,%SRCCOPY
      BitBlt hMonoDc,0,0,bmInfo.bmWidth - 1,bmInfo.bmHeight - 1,hColorDc,1,1,%MERGEPAINT
      hbmHighlight = SelectObject(hMonoDc,hbmHighlight)
      'Select old bitmap into color DC
      SelectObject hColorDc,hbmOld
      'clear background for disabled bitmap
      SelectObject hColorDc,hbmDisabled
      hbrPat = CreateSolidBrush(RGB_BTNFACE)
      hBrPat = SelectObject(hColorDc,hbrPat)
      PatBlt hColorDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,%PATCOPY
      DeleteObject SelectObject(hColorDc,hbrPat)
      SetBkColor hColorDc,RGB_WHITE
      SetTextColor hColorDc,RGB_BLACK
      'blt highlight edge
      hbrPat = CreateSolidBrush(RGB_BTNHIGHLIGHT)
      hbrPat = SelectObject(hColorDc,hbrPat)
      hbmHighlight = SelectObject(hMonoDc,hbmHighlight)
      BitBlt hColorDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,hMonoDc,0,0,PSDPxax
      DeleteObject SelectObject(hColorDc,hbrPat)
      hbmHighlight = SelectObject(hMonoDc,hbmHighlight)
      'blt shadow edge
      hbrPat = CreateSolidBrush(RGB_BTNSHADOW)
      hbrPat = SelectObject(hColorDc,hbrPat)
      hbmShadow = SelectObject(hMonoDc,hbmShadow)
      BitBlt hColorDc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,hMonoDc,0,0,PSDPxax
      DeleteObject SelectObject(hColorDc,hbrPat)
      hbmShadow = SelectObject(hMonoDc,hbmShadow)
      'For odbuts
    '  BorderBox hColorDc,1,0,0,bmInfo.bmHeight-1,bmInfo.bmWidth-1,RGB_BTNFACE,RGB_BTNFACE,1
      SelectObject hColorDc,hbmOld
      DeleteObject hbmShadow
      DeleteObject hbmHighlight
      ReleaseDc 0,hDc
      IF hMonoDc THEN
        DeleteDc hMonoDc
      END IF
      IF hColorDc THEN
        DeleteDc hColorDc
      END IF
      FUNCTION = hbmDisabled    
    Last edited by jcfuller; 20 Dec 2007, 10:29 AM.


    • #3
      Thanks for the code James. Unfortunately the problem I'm having is specific to the icon mask.

      In 16-bit colour depth "If SourceMask = 0" enables me to avoid the transparent part of the icon. In 32-bit colour depth it avoids most of it, bit seems to pick up splodges around the edge of the icon.