Jump to content

[SOLVED]Layer mask in GDI+


 Share

Go to solution Solved by UEZ,

Recommended Posts

So I wanted to apply custom shapes to images (like get a part of the image shaped as an specified ellipse). I looked, but could'n find any.

I ended up making something inspired by Photoshop's ability to Make layer mask's.

Here's an Example:

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

_GDIPlus_Startup()

$hImage=_GDIPlus_ImageLoadFromFile(@ScriptDir&"\1.png")
$hImage2=CreateLayerMask($hImage)
$hGraphics=_GDIPlus_ImageGetGraphicsContext($hImage2)
$hBrush=_GDIPlus_BrushCreateSolid(0xFFFFFFFF)
_GDIPlus_GraphicsFillEllipse($hGraphics, 10, 10, _GDIPlus_ImageGetWidth($hImage2)-20, _GDIPlus_ImageGetHeight($hImage2)-20, $hBrush)
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_GraphicsDispose($hGraphics)
$hBitmap=ApplyLayerMask($hImage, $hImage2)
_GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir&"\2.png")
_GDIPlus_ImageDispose($hImage)
_GDIPlus_ImageDispose($hImage2)
_GDIPlus_ImageDispose($hBitmap)

_GDIPlus_Shutdown()

Func CreateLayerMask($hImage)
$iWidth = _GDIPlus_ImageGetWidth($hImage)
$iHeight = _GDIPlus_ImageGetHeight($hImage)
$HBITMAP = _WinAPI_CreateBitmap($iWidth, $iHeight, 1, 32)
$hBmp = _GDIPlus_BitmapCreateFromHBITMAP($HBITMAP)
_WinAPI_DeleteObject($HBITMAP)
$hBitmap = _GDIPlus_BitmapCloneArea($hBmp, 0, 0, $iWidth, $iHeight, $GDIP_PXF32ARGB)
_GDIPlus_BitmapDispose($hBmp)
Return $hBitmap
EndFunc

Func ApplyLayerMask($hImage1, ByRef $hImage2, $bInvert=False)
If $bInvert Then
$iRBGA='000000FF'
Else
$iRBGA='FFFFFFFF'
EndIf
$iWidth = _GDIPlus_ImageGetWidth($hImage1)
$iHeight = _GDIPlus_ImageGetHeight($hImage1)
$HBITMAP = _WinAPI_CreateBitmap($iWidth, $iHeight, 1, 32)
$hBmp=_GDIPlus_BitmapCreateFromHBITMAP($HBITMAP)
_WinAPI_DeleteObject($HBITMAP)
$hBitmap = _GDIPlus_BitmapCloneArea($hBmp, 0, 0, $iWidth, $iHeight, $GDIP_PXF32ARGB)
_GDIPlus_BitmapDispose($hBmp)
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
_GDIPlus_GraphicsDrawImage($hGraphics, $hImage, 0, 0)
_GDIPlus_GraphicsDispose($hGraphics)
$tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
$tBitmapData2 = _GDIPlus_BitmapLockBits($hImage2, 0, 0, $iWidth, $iHeight, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
$tPixels = DllStructCreate("byte[" & $iHeight * $iWidth * 4 & "]", DllStructGetData($tBitmapData, "Scan0")) ; Create DLL structure for all pixels
$tPixels2 = DllStructCreate("byte[" & $iHeight * $iWidth * 4 & "]", DllStructGetData($tBitmapData2, "Scan0")) ; Create DLL structure for all pixels
$sPixels = DllStructGetData($tPixels, 1)
$sPixels2 = DllStructGetData($tPixels2, 1)
$iPixels=StringLen($sPixels)
$sPixels=StringMid($sPixels, 3, $iPixels-2)
$sPixels2=StringMid($sPixels2, 3, $iPixels-2)
$iPixels=StringLen($sPixels)
Dim $aPixels[$iPixels/8]
For $i=0 To $iPixels/8-1
If $iRBGA=StringMid($sPixels2, ($i*8)+1, 8) Then
$aPixels[$i]=StringMid($sPixels, ($i*8)+1, 8)
Else
$aPixels[$i]='00000000'
EndIf
Next
$sPixels=_ArrayToString($aPixels, "")
$sPixels="0x"&$sPixels
$sPixels1="0x"&$sPixels2
DllStructSetData($tPixels, 1, $sPixels)
_GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)
_GDIPlus_BitmapUnlockBits($hImage2, $tBitmapData2)

$tPixels = 0
$tPixels2 = 0
$tBitmapData = 0
$tBitmapData2 = 0

Return $hBitmap
EndFunc

Example image: http://green-tag.dk/AutoIt/1.png

(Use bigger image if you wish)

Problem is the speed. The bigger the image, the longer it takes, i just can't think of any way to make this faster. Any suggestions, are appreciated! :)

Thanks in advance :)

Edited by genius257
Makes it easy to see problem was solved, from topic list
Link to comment
Share on other sites

  • Solution

Try this:

#include <GDIPlus.au3>

_GDIPlus_Startup()

$hImage=_GDIPlus_ImageLoadFromFile(@ScriptDir & "1.png")
$hNewBitmap = _GDIPlus_ImageShapeCircle($hImage, _GDIPlus_ImageGetWidth($hImage) /2)
_GDIPlus_ImageSaveToFile($hNewBitmap, @ScriptDir & "2.png")
_GDIPlus_ImageDispose($hImage)
_GDIPlus_BitmapDispose($hNewBitmap)
_GDIPlus_Shutdown()
ShellExecute(@ScriptDir & "2.png")
Exit

Func _GDIPlus_ImageShapeCircle($hBitmap, $iRadius, $iTiling = 4) ;coded by UEZ 2012-12-17
    Local $iWidth = $iRadius * 2, $iHeight = $iWidth
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateTexture", "ptr", $hImage, "int", $iTiling, "int*", 0)
    If @error Then Return SetError(1, 0, 0)
    Local $hTexture = $aResult[3]
    $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
    If @error Then Return SetError(2, 0, 0)
    Local $hImage = $aResult[6]
    Local $hGfxCtxt = _GDIPlus_ImageGetGraphicsContext($hImage)
    _GDIPlus_GraphicsSetSmoothingMode($hGfxCtxt, 2)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "handle", $hGfxCtxt, "int", 2)
    _GDIPlus_GraphicsFillEllipse($hGfxCtxt, 0, 0, $iWidth, $iHeight, $hTexture)
    _GDIPlus_BrushDispose($hTexture)
    _GDIPlus_GraphicsDispose($hGfxCtxt)
    Return $hImage
EndFunc

Func _GDIPlus_ImageShapeCircle2($hBitmap, $iRadius, $fDX = 0, $fDY = 0, $iTiling = 4) ;coded by UEZ 2012-12-17
    Local $iWidth = $iRadius * 2
    If _GDIPlus_ImageGetWidth($hBitmap) < $iWidth Then $iWidth = _GDIPlus_ImageGetWidth($hBitmap)
    Local $iHeight = $iWidth
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateTexture2", "handle", $hBitmap, "int", $iTiling, "float", $fDX, "float", $fDY, "float", $iWidth, "float", $iHeight, "int*", 0)
    If @error Then Return SetError(1, 0, 0)
    Local $hTexture = $aResult[7]
    $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
    If @error Then Return SetError(2, 0, 0)
    Local $hImage = $aResult[6]
    Local $hGfxCtxt = _GDIPlus_ImageGetGraphicsContext($hImage)
    _GDIPlus_GraphicsSetSmoothingMode($hGfxCtxt, 2)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "handle", $hGfxCtxt, "int", 2)
    _GDIPlus_GraphicsFillEllipse($hGfxCtxt, 0, 0, $iWidth, $iHeight, $hTexture)
    _GDIPlus_BrushDispose($hTexture)
    _GDIPlus_GraphicsDispose($hGfxCtxt)
    Return $hImage
EndFunc

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

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...