NassauSky Posted October 24, 2023 Share Posted October 24, 2023 (edited) As per a previous thread, I spoke about saving an image displayed in the GUI (thanks @Andreik for clearing up the save to file feature), this is a continuation of the Speech Bubble project but a different issue regarding rotation of the graphic. The below simple app is almost done but I can't figure out 3 things: 1) Why doesn't it clear out the original image when drawing the rotated image 2) Why is the rotated image shifted over to the left and cropped 3) How to get it to draw an outline with the extra odd line between (Not as critical for the project) expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Local $hGUI, $hWnd, $hImage, $hGraphic, $cPic Local $outputImage = "SpeechBubble.png" FileDelete($outputImage) Local $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer") ConsoleWrite("Required Angle: " & $fAngle & @CRLF) ; Create GUI $hGUI = GUICreate("GDI+", 220, 220) $cPic = GUICtrlCreatePic('', 0, 0, 220, 220) $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $hImage = _GDIPlus_BitmapCreateFromScan0(220, 220) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) ; Draw a Triangle Global $tWidth = 220 Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = 110 - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphic, $aPoints, $hBrush) _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints, $hPen) ; Draw a circle Local $CircleDiameter = 150 Local $CircleX = (220 - $CircleDiameter) / 2 Local $CircleY = (220 - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrush) _GDIPlus_GraphicsDrawEllipse($hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPen) ; Create a matrix and rotate the image by $fAngle degrees ;Rotation Matrix Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0) BitmapToCtrl($hImage, $cPic) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage _GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Edited October 24, 2023 by NassauSky Clarify non critical component Link to comment Share on other sites More sharing options...
Nine Posted October 24, 2023 Share Posted October 24, 2023 (edited) Here a streamlined version of your script to show you a few flaws in your design. 1- If you ask to paint 2 things in the same graphic, well, those 2 things will show 2- By rotating a shape, you also rotating its 0,0 origin, see why I needed to adapt according a 45° clockwise rotation 3- I don't understand your question expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> Opt('MustDeclareVars', 1) Main() Func Main() Local $hGUI = GUICreate("GDI+", 220, 220) Local $idPic = GUICtrlCreatePic('', 10, 10, 200, 200) GUISetState() _GDIPlus_Startup() Local $hImage = _GDIPlus_BitmapCreateFromScan0(200, 200) Local $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsDrawRect($hGraphic, 25, 25, 120, 120) ; <<<<<<<<<< comment out this line, and only one shape will be shown Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixRotate($hMatrix, 45) _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) _GDIPlus_GraphicsDrawRect($hGraphic, 60, -60, 120, 120) ; <<<<<<<<<<<<<< need to adapt 0,0 origin BitmapToCtrl($hImage, $idPic) For $i = 1 To 800 If GUIGetMsg() = $GUI_EVENT_CLOSE Then ExitLoop Next _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_MatrixDispose($hMatrix) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() EndFunc ;==>Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc ;==>BitmapToCtrl Edited October 24, 2023 by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
NassauSky Posted October 24, 2023 Author Share Posted October 24, 2023 (edited) Thanks @Nine #1) OK let me modify my example to be closer to my desired end project since I think I see what you're saying and I do want to display 1 thing in the graphic then erase it and then display a 2nd in the graphic. Here is a modification of my thought which displays the 0 degree speech bubble then asks the user for a rotation upon button click. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Global $hGUI, $hWnd, $hImage, $hGraphic, $cPic, $idButton Global $outputImage = "SpeechBubble.png" Global $fAngle = 0 FileDelete($outputImage) ; Create GUI $hGUI = GUICreate("GDI+", 220, 240) $idButton = GUICtrlCreateButton("Angle", 0, 0, 100, 20) $cPic = GUICtrlCreatePic('', 0, 20, 220, 220) $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $hImage = _GDIPlus_BitmapCreateFromScan0(220, 220) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) ; Draw a Triangle Global $tWidth = 220 Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = 110 - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphic, $aPoints, $hBrush) _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints, $hPen) ; Draw a circle Local $CircleDiameter = 150 Local $CircleX = (220 - $CircleDiameter) / 2 Local $CircleY = (220 - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrush) _GDIPlus_GraphicsDrawEllipse($hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPen) BitmapToCtrl($hImage, $cPic) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton Global $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer") ConsoleWrite("Required Angle: " & $fAngle & @CRLF) SpeechBubbleRedraw() EndSwitch Until False ;GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage _GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Func SpeechBubbleRedraw() ; Create a matrix and rotate the image by $fAngle degrees Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0) BitmapToCtrl($hImage, $cPic) EndFunc #2) Thanks! That made sense i ran some tests and it looks good. #3) My example creates a speech bubble from an ellipse and a triangle but when you draw a line around each one individually it doesn't look like a speech bubble. I would need to be able to draw a line around the union of the 2 shapes if that makes sense. Edited October 24, 2023 by NassauSky Link to comment Share on other sites More sharing options...
Andreik Posted October 24, 2023 Share Posted October 24, 2023 (edited) Drawing rotated things it's very tricky. It's not just that you have to adjust (translate) the matrix before and after rotation to ensure a rotation around the center of your image but also you have to keep in mind that a rotated image might extend beyond the initial image dimensions. Let's say that the purple box is your bitmap and you have a rectangle in the middle of your image. When it's rotated at 45 deg the rectangle won't fit in your image unless is the rectangle is scaled down or image dimension increased. So it's pretty tricky to work with rotated images in GDI+ but it might be an easier solution if you detail your final goal. Edited October 24, 2023 by Andreik When the words fail... music speaks. Link to comment Share on other sites More sharing options...
NassauSky Posted October 25, 2023 Author Share Posted October 25, 2023 (edited) Thanks @Andreik, Yeah that's why I only need to create square images. In this case the Speech Bubble content will be a circle with enough space on it's 4 sides that when it rotates with a point, it shouldn't be clipped off. There is an example by @Lakes in a long thread at Posted August 30, 2010 about 1/3 down the page The QUICK 2D EXAMPLE This example is similar in a way to how it refreshes but can't figure exactly how it's code is refreshing and clearing the images in relation to what I want to do. Edited October 25, 2023 by NassauSky Link to comment Share on other sites More sharing options...
NassauSky Posted October 25, 2023 Author Share Posted October 25, 2023 (edited) Not pretty but this is what I'm working with now, still needs rotation and optionally creating a border around the outside edge which doesn't cut through the triangle. Trying some rotation techniques. Some remarked out. CalculateCoordinates func might be the start of getting it rotated correctly. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Global $hGUI, $hWnd, $hImage, $hGraphic, $cPic, $idButton Global $outputImage = "SpeechBubble.png" Global $fAngle = 0 Global Const $nPI = 3.1415926535897932384626433832795 Global $iRadius = 110 Global $iCenter = 110 Global $iSize = 220 Global $nImgWidth = 220 FileDelete($outputImage) ; Create GUI $hGUI = GUICreate("GDI+", $nImgWidth, 240) $idButton = GUICtrlCreateButton("Angle", 0, 0, 100, 20) $cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $hImage = _GDIPlus_BitmapCreateFromScan0($nImgWidth, $nImgWidth) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) DrawTriangle($hGraphic, $hBrush, $hPen) DrawCircle($hGraphic, $hBrush, $hPen) BitmapToCtrl($hImage, $cPic) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton Global $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer", 45) ConsoleWrite("Required Angle: " & $fAngle & @CRLF) SpeechBubbleRedraw($hGraphic, $hImage, $hBrush, $hPen) EndSwitch Until False ;GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage _GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) ;If FileExists($outputImage2) Then ShellExecute($outputImage2) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Func DrawTriangle($hGraphicT, $hBrushT, $hPenT) ; Draw a Triangle Global $tWidth = $nImgWidth Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = 110 - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphicT, $aPoints, $hBrushT) _GDIPlus_GraphicsDrawPolygon($hGraphicT, $aPoints, $hPenT) EndFunc Func DrawCircle($hGraphicT, $hBrushT, $hPenT) ; Draw a circle Local $CircleDiameter = 150 Local $CircleX = ($nImgWidth - $CircleDiameter) / 2 Local $CircleY = ($nImgWidth - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrushT ) _GDIPlus_GraphicsDrawEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPenT ) EndFunc Func SpeechBubbleRedraw($hGraphicT, $hImageT, $hBrushT, $hPenT) ; Create a matrix and rotate the image by $fAngle degrees _GDIPlus_GraphicsClear($hGraphicT, 0x00FFFFFF) ; Clear with white (0xFFFFFFFF) or any other desired color ;~ Local $R = ($nPI / 2) - ($fAngle * ($nPI /180)) ;~ Local $iX1 = Int($iCenter + Cos($R) * $iRadius) ;~ Local $iY1 = Int($iCenter - Sin($R) * $iRadius) ;~ ;Local $aCoords = CalculateCoordinates($nImgWidth, $fAngle) ;~ ;Local $iX1 = $aCoords[0] ;~ ;Local $iY1 = $aCoords[1] ;~ ConsoleWrite("Given angle: " & $fAngle & " Result x/y: " & $iX1 & " / " & $iY1 & @CRLF) ;~ Local $hMatrix = _GDIPlus_MatrixCreate() ;~ _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") ;~ _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) ;~ _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, $iY1, $iY1) Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_GraphicsSetTransform($hGraphicT, $hMatrix) DrawTriangle($hGraphicT, $hBrushT, $hPenT) DrawCircle($hGraphicT, $hBrushT, $hPenT) GUICtrlDelete ( $cPic ) $cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) GUISetState() BitmapToCtrl($hImageT, $cPic) _GDIPlus_ImageSaveToFile($hImageT, $outputImage) EndFunc Func CalculateCoordinates($nImgWidth, $fAngle) Local $xx, $yy Local $nImgWidthHalf = $nImgWidth / 2 Switch $fAngle Case 0 $xx = 0 $yy = 0 Case 1 To 44 $xx = $fAngle $yy = 0 Case 45 $xx = 45 $yy = -($nImgWidth / 2) Case 46 To 89 $xx = $nImgWidthHalf $yy = -($nImgWidth / 2) Case 90 $xx = 0 $yy = -($nImgWidth) Case 91 To 134 $xx = 0 $yy = -($nImgWidth) Case 135 $xx = -($nImgWidth) $yy = -($nImgWidth) Case 136 To 179 $xx = -($nImgWidth) $yy = -($nImgWidth) Case 180 $xx = -($nImgWidth) $yy = -($nImgWidth) Case 181 To 224 $xx = -($nImgWidth) $yy = -($nImgWidthHalf) Case 225 $xx = -($nImgWidth) $yy = -($nImgWidthHalf) Case 226 To 269 $xx = 0 $yy = 0 Case 270 $xx = 0 $yy = 0 Case 271 To 314 $xx = $fAngle - 360 $yy = 0 Case 315 $xx = $fAngle - 360 $yy = 0 Case 316 To 359 $xx = $fAngle - 360 $yy = -($nImgWidth / 2) EndSwitch Local $aResult[2] $aResult[0] = $xx $aResult[1] = $yy ConsoleWrite("Given angle: " & $fAngle & " Result x/y: " & $xx & "/" & $yy & @CRLF) Return $aResult EndFunc Edited October 25, 2023 by NassauSky Link to comment Share on other sites More sharing options...
ahmet Posted October 25, 2023 Share Posted October 25, 2023 (edited) Here is your code modified from first post expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Local $hGUI, $hWnd, $hImage, $hGraphic, $cPic Local $outputImage = "SpeechBubble.png" FileDelete($outputImage) Local $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer",10) ConsoleWrite("Required Angle: " & $fAngle & @CRLF) ; Create GUI $hGUI = GUICreate("GDI+", 220, 220) $cPic = GUICtrlCreatePic('', 0, 0, 220, 220) $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $hImage = _GDIPlus_BitmapCreateFromScan0(220, 220) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) ; Draw a Triangle Global $tWidth = 220 Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = 110 - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphic, $aPoints, $hBrush) _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints, $hPen) ; Draw a circle Local $CircleDiameter = 150 Local $CircleX = (220 - $CircleDiameter) / 2 Local $CircleY = (220 - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrush) _GDIPlus_GraphicsDrawEllipse($hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPen) ;This in new - pen for drawing axes lines Local $hPenArrow = _GDIPlus_PenCreate(0xFF000000, 1) _GDIPlus_PenSetEndCap($hPenArrow, $GDIP_LINECAPARROWANCHOR) Local $hPenArrow_ForRotated = _GDIPlus_PenCreate(0xFFF00F00, 1);yellow line - rotated _GDIPlus_PenSetEndCap($hPenArrow_ForRotated, $GDIP_LINECAPARROWANCHOR) Local $fAxesCenterX=$CircleX+$CircleDiameter/2, $fAxesCenterY=$CircleY+$CircleDiameter/2;center coordinates ConsoleWrite("X=" & $fAxesCenterX & "; Y=" & $fAxesCenterY & @CRLF) _GDIPlus_GraphicsDrawLine($hGraphic,$fAxesCenterX,$fAxesCenterY,$fAxesCenterX+100,$fAxesCenterY,$hPenArrow);notice value of center coordinates ; Create a matrix and rotate the image by $fAngle degrees ;Rotation Matrix Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix,+$fAxesCenterX,+$fAxesCenterY);https://www.vbforums.com/showthread.php?841185-GDIPLUS-how-rotate-an-image-by-a-center&s=f20f7a20e35573308599859c5bb9c70d&p=5123549&viewfull=1#post5123549 _GDIPlus_MatrixRotate($hMatrix, $fAngle, False) _GDIPlus_MatrixTranslate($hMatrix,-$fAxesCenterX,-$fAxesCenterY) _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix);https://www.vbforums.com/showthread.php?841185-GDIPLUS-how-rotate-an-image-by-a-center&s=f20f7a20e35573308599859c5bb9c70d&p=5123549&viewfull=1#post5123549 _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0);"Origin display rotated" - comment this line to see axes BitmapToCtrl($hImage, $cPic) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage ;_GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_PenDispose($hPenArrow) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() ;If FileExists($outputImage) Then ShellExecute($outputImage) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Rotation about center taken from here. Edited October 25, 2023 by ahmet NassauSky 1 Link to comment Share on other sites More sharing options...
UEZ Posted October 25, 2023 Share Posted October 25, 2023 (edited) I found two old scripts - maybe it helps: expandcollapse popup;idea taken from http://codepen.io/neilorangepeel/pen/mJoxaJ ;coded by UEZ build 2015-08-20 #pragma compile(Icon, "AutoIt_Main_v10_48x48_only_RGB-A.ico") #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/so /pe /rm #AutoIt3Wrapper_Run_After=del /f /q "%scriptdir%\%scriptfile%_stripped.au3" #include <GDIPlus.au3> #include <GuiConstantsEx.au3> #include <WindowsConstants.au3> AutoItSetOption("GUIOnEventMode", 1) _GDIPlus_Startup() Global $i Global Const $iW = 500, $iH = 700, $sTitle = "GDI+ Ascending Rectangles / fps: " Global Const $hGUI = GUICreate($sTitle & 0, $iW, $iH) GUISetState() Global Const $hDC = _WinAPI_GetDC($hGUI) Global Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Global Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC) Global Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap) Global Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer) _GDIPlus_GraphicsSetPixelOffsetMode($hCanvas, 4) Global Const $iAmount = 24 Global $aData[$iAmount][13] = [[]], $hEffect, $iFPS = 0 For $i = 0 To UBound($aData) - 1 $aData[$i][0] = Random(20, $iW / 4, 1) ;size $aData[$i][1] = _GDIPlus_BitmapCreateFromScan0($aData[$i][0], $aData[$i][0]) ;hBmp $aData[$i][2] = _GDIPlus_ImageGetGraphicsContext($aData[$i][1]) ;hGfx _GDIPlus_GraphicsSetPixelOffsetMode($aData[$i][2], 4) _GDIPlus_GraphicsSetSmoothingMode($aData[$i][2], 4) $aData[$i][3] = Random(0, $iW - $aData[$i][0], 1) ;x pos $aData[$i][4] = Random($iH, $iH * 3) ;y pos $aData[$i][5] = Random(1, 5) ;vy $aData[$i][6] = Random(0x08, 0xA0, 1) * 0x1000000 + Random(0x00000, 0xFFFFFF, 1) ;random color alpha + rgb $aData[$i][7] = _GDIPlus_BrushCreateSolid($aData[$i][6]) ;hBrush $aData[$i][8] = _GDIPlus_PenCreate(0x20505050, Random(1, Ceiling($aData[$i][0] / 14))) ;hPen $aData[$i][9] = Random(-6, 6) ;roation $aData[$i][10] = _GDIPlus_MatrixCreate() ;hMatrix $aData[$i][11] = Random(-50, 50) ;sin value $aData[$i][12] = Random(-2, 2) ;increase value for sin Next AdlibRegister("CalcFPS", 1000) GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit") Anim() While Sleep(30) Anim() WEnd Func _Exit() AdlibUnRegister("CalcFPS") For $i = 0 To UBound($aData) - 1 _GDIPlus_GraphicsDispose($aData[$i][2]) _GDIPlus_BitmapDispose($aData[$i][1]) _GDIPlus_BrushDispose($aData[$i][7]) _GDIPlus_PenDispose($aData[$i][8]) _GDIPlus_MatrixDispose($aData[$i][10]) Next _GDIPlus_GraphicsDispose($hCanvas) _WinAPI_SelectObject($hDC_backbuffer, $DC_obj) _WinAPI_DeleteDC($hDC_backbuffer) _WinAPI_DeleteObject($hHBitmap) _WinAPI_ReleaseDC($hGUI, $hDC) _GDIPlus_Shutdown() GUIDelete() Exit EndFunc Func Anim() Local $i, $fX, $fY, $fW, $fH _GDIPlus_GraphicsClear($hCanvas, 0xFFFAFAFF) For $i = 0 To UBound($aData) - 1 _GDIPlus_GraphicsClear($aData[$i][2], 0x00000000) _GDIPlus_MatrixTranslate($aData[$i][10], $aData[$i][0] / 2, $aData[$i][0] / 2) _GDIPlus_MatrixRotate($aData[$i][10], $aData[$i][9]) _GDIPlus_MatrixTranslate($aData[$i][10], -$aData[$i][0] / 2, -$aData[$i][0] / 2) _GDIPlus_GraphicsSetTransform($aData[$i][2], $aData[$i][10]) $fX = $aData[$i][0] / 5 $fY = $fX $fW = $aData[$i][0] - $aData[$i][0] / 2.5 $fH = $fW _GDIPlus_GraphicsFillRect($aData[$i][2], $fX, $fY, $fW, $fH, $aData[$i][7]) _GDIPlus_GraphicsDrawRect($aData[$i][2], $fX, $fY, $fW, $fH, $aData[$i][8]) _GDIPlus_GraphicsDrawImageRect($hCanvas, $aData[$i][1], $aData[$i][3] + Sin($aData[$i][11] / 100) * 100, $aData[$i][4], $aData[$i][0], $aData[$i][0]) $aData[$i][11] += $aData[$i][12] $aData[$i][4] -= $aData[$i][5] If $aData[$i][4] < -$aData[$i][0] * 2 Then _GDIPlus_MatrixDispose($aData[$i][10]) _GDIPlus_GraphicsDispose($aData[$i][2]) _GDIPlus_BitmapDispose($aData[$i][1]) $aData[$i][0] = Random(20, $iW / 4, 1) ;size $aData[$i][1] = _GDIPlus_BitmapCreateFromScan0($aData[$i][0], $aData[$i][0]) ;hBmp $aData[$i][2] = _GDIPlus_ImageGetGraphicsContext($aData[$i][1]) ;hGfx _GDIPlus_GraphicsSetPixelOffsetMode($aData[$i][2], 4) _GDIPlus_GraphicsSetSmoothingMode($aData[$i][2], 4) $aData[$i][3] = Random(0, $iW - $aData[$i][0], 1) ;x pos $aData[$i][4] = $iH $aData[$i][5] = Random(1, 5) ;vy $aData[$i][6] = Random(0x08, 0xA0, 1) * 0x1000000 + Random(0x00000, 0xFFFFFF, 1) ;random color _GDIPlus_BrushSetSolidColor($aData[$i][7], $aData[$i][6]) $aData[$i][9] = Random(-6, 6) ;roation $aData[$i][10] = _GDIPlus_MatrixCreate() ;hMatrix EndIf Next _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY) $iFPS += 1 EndFunc Func CalcFPS() WinSetTitle($hGUI, "", $sTitle & $iFPS) $iFPS = 0 EndFunc expandcollapse popup#include <GDIPlusConstants.au3> #include <WindowsConstants.au3> #include <GDIPlus.au3> #include <WinAPISysWin.au3> ;example #include <GDIPlus.au3> _GDIPlus_Startup() Local Const $STM_SETIMAGE = 0x0172, $iBGTColor = 0xFEDCBA, $iW = 70, $iH = 45 Local $hGUI_ToolTip = GUICreate("", $iW, $iH, -1, -1, $WS_POPUP + $WS_DISABLED, $WS_EX_LAYERED + $WS_EX_TOOLWINDOW) GUISetBkColor($iBGTColor, $hGUI_ToolTip) ;set GUI background color Local $iPic = GUICtrlCreatePic("", 0, 0, $iW, $iH) GUISetState(@SW_SHOW, $hGUI_ToolTip) _WinAPI_SetLayeredWindowAttributes($hGUI_ToolTip, $iBGTColor, 0xFF) Local $hHBmp_TP = _GDIPlus_CreateToolTipBitmap("Hallo", $iW, $iH) Local $hB = GUICtrlSendMsg($iPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBmp_TP) If $hB Then _WinAPI_DeleteObject($hB) Do Until GUIGetMsg() = -3 _WinAPI_DeleteObject($hHBmp_TP) _GDIPlus_Shutdown() GUIDelete() Exit ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GDIPlus_CreateToolTipBitmap ; Description ...: Creates a tooltip like window using GDI+ ; Syntax ........: _GDIPlus_CreateToolTipBitmap($sText[, $iW = 70[, $iH = 50[, $sFont = "Arial"[, $fFontSize = 11[, ; $iBGColor = 0xFFFFFFFF[, $iFontColor = 0xFF000000[, $iRadius = 8[, $hImage = 0[, $iImgPosX = 8[, ; $iImgPosY = 4[, $iImgW = 16[, $iImgH = 16[, $bGDIBmp = 1]]]]]]]]]]]]]) ; Parameters ....: $sText - A string value. ; $iW - [optional] An integer value. Default is 70. ; $iH - [optional] An integer value. Default is 50. ; $sFont - [optional] A string value. Default is "Arial". ; $fFontSize - [optional] A boolean value. Default is 11. ; $iBGColor - [optional] An integer value. Default is 0xFFFFFFFF. ; $iFontColor - [optional] An integer value. Default is 0xFF000000. ; $iRadius - [optional] An integer value. Default is 8. ; $hImage - [optional] A handle value. Default is 0. ; $iImgPosX - [optional] An integer value. Default is 8. ; $iImgPosY - [optional] An integer value. Default is 4. ; $iImgW - [optional] An integer value. Default is 16. ; $iImgH - [optional] An integer value. Default is 16. ; $bGDIBmp - [optional] A binary value. Default is 1. ; Return values .: bitmap handle (GDI+ format bitmap) ; Author ........: UEZ ; Modified ......: ; Remarks .......: AutoIt version 3.3.9.18 or higher is needed ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _GDIPlus_CreateToolTipBitmap($sText, $iW = 70, $iH = 50, $sFont = "Arial", $fFontSize = 11, $iBGColor = 0xFFFFFFFF, $iFontColor = 0xFF000000, $iRadius = 8, $hImage = 0, $iImgPosX = 8, $iImgPosY = 4, $iImgW = 16, $iImgH = 16, $bGDIBmp = 1) Local $iX = 0, $iY = 0, $iPenSize = 1, $iSize = 12, $iSize2 = $iSize / 2, $iDX = $iW / 2 Local $iWidth = $iW - $iPenSize, $iHeight = $iH - $iPenSize - $iSize Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hCtxt, $GDIP_SMOOTHINGMODE_HIGHQUALITY) _GDIPlus_GraphicsSetTextRenderingHint($hCtxt, $GDIP_TEXTRENDERINGHINTANTIALIASGRIDFIT) Local $hPath = _GDIPlus_PathCreate() _GDIPlus_PathAddArc($hPath, $iX + $iWidth - ($iRadius * 2), $iY, $iRadius * 2, $iRadius * 2, 270, 90) _GDIPlus_PathAddArc($hPath, $iX + $iWidth - ($iRadius * 2), $iY + $iHeight - ($iRadius * 2), $iRadius * 2, $iRadius * 2, 0, 90) _GDIPlus_PathAddLine($hPath, $iX + $iWidth - ($iRadius * 2), $iY + $iHeight, $iDX + $iSize2, $iY + $iHeight) _GDIPlus_PathAddLine($hPath, $iDX + $iSize2, $iY + $iHeight, $iX + $iDX, $iY + $iHeight + $iSize) _GDIPlus_PathAddLine($hPath, $iX + $iDX, $iY + $iHeight + $iSize, $iX + $iDX - $iSize2, $iY + $iHeight) _GDIPlus_PathAddArc($hPath, $iX, $iY + $iHeight - ($iRadius * 2), $iRadius * 2, $iRadius * 2, 90, 90) _GDIPlus_PathAddArc($hPath, $iX, $iY, $iRadius * 2, $iRadius * 2, 180, 90) _GDIPlus_PathCloseFigure($hPath) Local $hBrush = _GDIPlus_BrushCreateSolid($iBGColor) _GDIPlus_GraphicsFillPath($hCtxt, $hPath, $hBrush) Local $hPen = _GDIPlus_PenCreate(0xFF000000, $iPenSize) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen) Local $hFamily = _GDIPlus_FontFamilyCreate($sFont) Local $hFont = _GDIPlus_FontCreate($hFamily, $fFontSize) Local $hFormat = _GDIPlus_StringFormatCreate() Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iWidth, $iHeight) _GDIPlus_StringFormatSetAlign($hFormat, 1) Local $aMeasure = _GDIPlus_GraphicsMeasureString($hCtxt, $sText, $hFont, $tLayout, $hFormat) DllStructSetData($tLayout, "Y", ($iHeight - DllStructGetData($aMeasure[0], "Height")) / 2) _GDIPlus_BrushSetSolidColor($hBrush, $iFontColor) _GDIPlus_GraphicsDrawStringEx($hCtxt, $sText, $hFont, $tLayout, $hFormat, $hBrush) If $hImage Then _GDIPlus_GraphicsSetInterpolationMode($hCtxt, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) _GDIPlus_GraphicsDrawImageRectRect($hCtxt, $hImage, 0, 0, _GDIPlus_ImageGetWidth($hImage), _GDIPlus_ImageGetHeight($hImage), $iImgPosX, $iImgPosY, $iImgW, $iImgH) EndIf _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_FontDispose($hFont) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_PathDispose($hPath) _GDIPlus_BrushDispose($hBrush) _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hCtxt) If $bGDIBmp Then Local $hGDIBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _GDIPlus_BitmapDispose($hBitmap) Return $hGDIBmp EndIf Return $hBitmap EndFunc ;==>_GDIPlus_CreateToolTipBitmap Edited October 25, 2023 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 More sharing options...
Solution ioa747 Posted October 25, 2023 Solution Share Posted October 25, 2023 here is my approach, with out rotate expandcollapse popup; https://www.autoitscript.com/forum/topic/211009-create-a-custom-angled-speech-bubble/?do=findComment&comment=1525867 #include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Global $hGUI, $hWnd, $hImage, $hGraphic, $cPic, $idButton Global $outputImage = "SpeechBubble.png" Global $fAngle = 0 Global $nImgWidth = 220 FileDelete($outputImage) ; Create GUI $hGUI = GUICreate("GDI+", $nImgWidth, 240) $idButton = GUICtrlCreateButton("Angle", 0, 0, 100, 20) $cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $hImage = _GDIPlus_BitmapCreateFromScan0($nImgWidth, $nImgWidth) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) DrawBubble($hGraphic, $hBrush, $hPen, 0) BitmapToCtrl($hImage, $cPic) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton Global $fAngle = InputBox("Enter Angle", "Please enter the angle of the speech bubble pointer", 45) ConsoleWrite("Required Angle: " & $fAngle & @CRLF) SpeechBubbleRedraw($hGraphic, $hImage, $hBrush, $hPen, $fAngle) EndSwitch Until False ;GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage _GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) ;If FileExists($outputImage2) Then ShellExecute($outputImage2) EndFunc ;==>_Main ;---------------------------------------------------------------------------------------- Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc ;==>BitmapToCtrl ;---------------------------------------------------------------------------------------- Func DrawBubble($hGraphicT, $hBrushT, $hPenT, $iAngle = 135) ; Draw a Triangle Local Const $nPI = 3.1415926535897932384626433832795 Local $Deg, $R, $iX1, $iY1, $iRadius Local $iCenter = $nImgWidth / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points ;b $iRadius = $nImgWidth / 2 $Deg = $iAngle $R = ($nPI / 2) - ($Deg * ($nPI / 180)) $iX1 = $iCenter + Cos($R) * $iRadius $iY1 = $iCenter - Sin($R) * $iRadius $aPoints[2][0] = $iX1 $aPoints[2][1] = $iY1 ;ConsoleWrite("b=" & $aPoints[2][0] & ", " & $aPoints[2][1] & @CRLF) ;c $iRadius = 25 $Deg = $Deg + 90 $R = ($nPI / 2) - ($Deg * ($nPI / 180)) $iX1 = $iCenter + Cos($R) * $iRadius $iY1 = $iCenter - Sin($R) * $iRadius $aPoints[3][0] = $iX1 $aPoints[3][1] = $iY1 ;ConsoleWrite("c=" & $aPoints[3][0] & ", " & $aPoints[3][1] & @CRLF) ;a $iRadius = 25 $Deg = $Deg + 180 $R = ($nPI / 2) - ($Deg * ($nPI / 180)) $iX1 = $iCenter + Cos($R) * $iRadius $iY1 = $iCenter - Sin($R) * $iRadius $aPoints[1][0] = $iX1 $aPoints[1][1] = $iY1 ;ConsoleWrite("a=" & $aPoints[1][0] & ", " & $aPoints[1][1] & @CRLF) _GDIPlus_GraphicsFillPolygon($hGraphicT, $aPoints, $hBrushT) _GDIPlus_GraphicsDrawPolygon($hGraphicT, $aPoints, $hPenT) ; Draw a circle Local $CircleDiameter = 150 Local $CircleX = ($nImgWidth - $CircleDiameter) / 2 Local $CircleY = ($nImgWidth - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse($hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrushT) _GDIPlus_GraphicsDrawEllipse($hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPenT) ;hide tail $iRadius = ($CircleDiameter / 2) + 1 $Deg = $iAngle $R = ($nPI / 2) - ($Deg * ($nPI / 180)) $iX1 = $iCenter + Cos($R) * $iRadius $iY1 = $iCenter - Sin($R) * $iRadius $hPenT = _GDIPlus_PenCreate(0xFF00FF00, 14) _GDIPlus_GraphicsDrawLine($hGraphicT, $iCenter, $iCenter, $iX1, $iY1, $hPenT) EndFunc ;==>DrawBubble ;---------------------------------------------------------------------------------------- Func SpeechBubbleRedraw($hGraphicT, $hImageT, $hBrushT, $hPenT, $iAngle = 135) _GDIPlus_GraphicsClear($hGraphicT, 0x00FFFFFF) ; Clear with white (0xFFFFFFFF) or any other desired color DrawBubble($hGraphicT, $hBrushT, $hPenT, $iAngle) GUICtrlDelete($cPic) $cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) GUISetState() BitmapToCtrl($hImageT, $cPic) _GDIPlus_ImageSaveToFile($hImageT, $outputImage) EndFunc ;==>SpeechBubbleRedraw NassauSky 1 I know that I know nothing Link to comment Share on other sites More sharing options...
Andreik Posted October 25, 2023 Share Posted October 25, 2023 (edited) This is a basic start but this script can be improved. expandcollapse popup#include <GDIPlus.au3> $hMain = GUICreate('Test', 400, 400) $cPic = GUICtrlCreatePic('', 0, 0, 400, 400) GUISetState(@SW_SHOW, $hMain) _GDIPlus_Startup() $hBubble = SpeechBubble(400, 400, 'Yayyy!' & @CRLF & 'This is my bubble.') BitmapRotate($hBubble, 45) BitmapToCtrl($hBubble, $cPic) Do Until GUIGetMsg() = -3 _GDIPlus_BitmapDispose($hBubble) _GDIPlus_Shutdown() Func SpeechBubble($iW, $iH, $sString, $iBubbleColor = 0xFF1D3557, $iTextColor = 0xFFFFFFFF, $sFontFamily = 'Arial', $iFontSize = 15, $iPadding = 25) Local $aTriangle[4][2] = [[3, 0], [10, Int($iH/2)], [40, Int($iH/2) - 20], [40, Int($iH/2) + 20]] Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontFamily) Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize) Local $hFormat = _GDIPlus_StringFormatCreate() Local $hBrush = _GDIPlus_BrushCreateSolid($iBubbleColor) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH) Local $hPath = _GDIPlus_PathCreate(1) _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2) _GDIPlus_PathAddEllipse($hPath, $iPadding, $iPadding, $iW - 2 * $iPadding, $iH - 2 * $iPadding) _GDIPlus_PathAddPolygon($hPath, $aTriangle) _GDIPlus_GraphicsFillPath($hGraphics, $hPath, $hBrush) _GDIPlus_BrushSetSolidColor($hBrush, $iTextColor) _GDIPlus_GraphicsDrawStringEx($hGraphics, $sString, $hFont, $tLayout, $hFormat, $hBrush) _GDIPlus_PathDispose($hPath) _GDIPlus_BrushDispose($hBrush) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc Func BitmapRotate(ByRef $hBitmap, $iAngle) Local $iW = _GDIPlus_ImageGetWidth($hBitmap) Local $iH = _GDIPlus_ImageGetHeight($hBitmap) Local $hNew = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hNew) Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, $iW / 2, $iH / 2) _GDIPlus_MatrixRotate($hMatrix, $iAngle) _GDIPlus_GraphicsSetTransform($hGraphics, $hMatrix) _GDIPlus_MatrixTranslate($hMatrix, -$iW / 2, -$iH / 2) _GDIPlus_GraphicsSetTransform($hGraphics, $hMatrix) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) $hBitmap = $hNew EndFunc Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Or something like this if you don't want to keep tracking your bitmaps for further release of resources: expandcollapse popup#include <GDIPlus.au3> $hMain = GUICreate('Test', 400, 400) $cPic = GUICtrlCreatePic('', 0, 0, 400, 400) GUISetState(@SW_SHOW, $hMain) SpeechBubble($cPic, 400, 400, 'Yayyy!' & @CRLF & 'This is my bubble.', 45) Do Until GUIGetMsg() = -3 Func SpeechBubble($cCtrl, $iW, $iH, $sString, $iAngle = 0, $iBubbleColor = 0xFF1D3557, $iTextColor = 0xFFFFFFFF, $sFontFamily = 'Arial', $iFontSize = 15, $iPadding = 25) Local $aTriangle[4][2] = [[3, 0], [10, Int($iH/2)], [40, Int($iH/2) - 20], [40, Int($iH/2) + 20]] _GDIPlus_Startup() Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontFamily) Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize) Local $hFormat = _GDIPlus_StringFormatCreate() Local $hBrush = _GDIPlus_BrushCreateSolid($iBubbleColor) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH) Local $hPath = _GDIPlus_PathCreate(1) _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2) _GDIPlus_PathAddEllipse($hPath, $iPadding, $iPadding, $iW - 2 * $iPadding, $iH - 2 * $iPadding) _GDIPlus_PathAddPolygon($hPath, $aTriangle) _GDIPlus_GraphicsFillPath($hGraphics, $hPath, $hBrush) _GDIPlus_BrushSetSolidColor($hBrush, $iTextColor) _GDIPlus_GraphicsDrawStringEx($hGraphics, $sString, $hFont, $tLayout, $hFormat, $hBrush) BitmapRotate($hBitmap, $iAngle) BitmapToCtrl($hBitmap, $cCtrl) _GDIPlus_PathDispose($hPath) _GDIPlus_BrushDispose($hBrush) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_Shutdown() EndFunc Func BitmapRotate(ByRef $hBitmap, $iAngle) Local $iW = _GDIPlus_ImageGetWidth($hBitmap) Local $iH = _GDIPlus_ImageGetHeight($hBitmap) Local $hNew = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hNew) Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, $iW / 2, $iH / 2) _GDIPlus_MatrixRotate($hMatrix, $iAngle) _GDIPlus_GraphicsSetTransform($hGraphics, $hMatrix) _GDIPlus_MatrixTranslate($hMatrix, -$iW / 2, -$iH / 2) _GDIPlus_GraphicsSetTransform($hGraphics, $hMatrix) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) $hBitmap = $hNew EndFunc Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Edited October 25, 2023 by Andreik NassauSky 1 When the words fail... music speaks. Link to comment Share on other sites More sharing options...
NassauSky Posted October 25, 2023 Author Share Posted October 25, 2023 Thanks @Nine@Andreik@ahmet@UEZ@ioa747 I needed some of that smelling salt you all provided. @ahmet that finally made some sense to me, speaking about the rotation alone, the translation was the biggest part I was missing as per @Nine and @Andreik might have been leading to. @ioa747 wow, some classic geometry math I have to brush up on. Is that "hide tail" section drawing over the piece of the border line that I wanted gone? I'm going to run with that without knowing much about the speed of the drawing technique. I'll still keep my eye on this post if there are any tweaks or alternatives (one of which I see might just be posted by @Andreik. Thanks all! Link to comment Share on other sites More sharing options...
NassauSky Posted October 25, 2023 Author Share Posted October 25, 2023 @Andreik wow some fancy tricks and again quite a bit of gdi+ manipulation you have going there with embedding the text. I was going to add text in another way so that might help too! Link to comment Share on other sites More sharing options...
ioa747 Posted October 25, 2023 Share Posted October 25, 2023 7 minutes ago, NassauSky said: Is that "hide tail" section drawing over the piece of the border line that I wanted gone? yes it does exactly that Thanks NassauSky 1 I know that I know nothing Link to comment Share on other sites More sharing options...
NassauSky Posted October 25, 2023 Author Share Posted October 25, 2023 (edited) Like I said I am happy with @ioa747 's solution and have that as a crutch now. Just now I'm putting everyone's minds together I got this code I pieced together and at first I posted that I couldn't understand how it wasn't clearing the picture control. I got it now. This is the alternative I might use. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Local $aCanvas, $hImage, $hGraphic Global $hGUI, $hWnd, $idButton, $cPic Global $outputImage = "SpeechBubble.png" Global Const $nPI = 3.1415926535897932384626433832795 Global $fAngle = 0 Global $nImgWidth = 220 Global $CircleDiameter = 150 Global $iCenter = $nImgWidth / 2 FileDelete($outputImage) ; Create GUI $hGUI = GUICreate("GDI+", $nImgWidth, 240) $idButton = GUICtrlCreateButton("Angle", 0, 0, 100, 20) ;$cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) $cPic = CreatePictureControl() $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $aCanvas = CreateGraphicContext() $hImage = $aCanvas[0] $hGraphic = $aCanvas[1] ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) DrawTriangle($hGraphic, $hBrush, $hPen) DrawCircle($hGraphic, $hBrush, $hPen) ClearExtraArcLine($hGraphic) BitmapToCtrl($hImage, $cPic) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton Global $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer", 45) ConsoleWrite("Required Angle: " & $fAngle & @CRLF) SpeechBubbleRedraw($hGraphic, $hImage, $hBrush, $hPen) EndSwitch Until False ;GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage _GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Func CreatePictureControl() GUICtrlDelete($cPic) Local $cPicT = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) GUISetState() Return $cPicT EndFunc Func CreateGraphicContext() Local $hImageT = _GDIPlus_BitmapCreateFromScan0($nImgWidth, $nImgWidth) Local $hGraphicT = _GDIPlus_ImageGetGraphicsContext($hImageT) Local $aCanvas[2] $aCanvas[0]=$hImageT $aCanvas[1]=$hGraphicT Return $aCanvas EndFunc Func DrawTriangle($hGraphicT, $hBrushT, $hPenT) ; Draw a Triangle Global $tWidth = $nImgWidth Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = 110 - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphicT, $aPoints, $hBrushT) _GDIPlus_GraphicsDrawPolygon($hGraphicT, $aPoints, $hPenT) EndFunc Func DrawCircle($hGraphicT, $hBrushT, $hPenT) ; Draw a circle Local $CircleX = ($nImgWidth - $CircleDiameter) / 2 Local $CircleY = ($nImgWidth - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrushT ) _GDIPlus_GraphicsDrawEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPenT ) EndFunc Func SpeechBubbleRedraw($hGraphicT, $hImageT, $hBrushT, $hPenT) ; Create a matrix and rotate the image by $fAngle degrees _GDIPlus_GraphicsClear($hGraphicT, 0x00FFFFFF) ; Clear with white (0xFFFFFFFF) or any other desired color Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix,+110,+110) _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_MatrixTranslate($hMatrix,-110,-110) _GDIPlus_GraphicsSetTransform($hGraphicT, $hMatrix) DrawTriangle($hGraphicT, $hBrushT, $hPenT) DrawCircle($hGraphicT, $hBrushT, $hPenT) ClearExtraArcLine($hGraphicT) CreatePictureControl() ;Got it BitmapToCtrl($hImageT, $cPic) _GDIPlus_ImageSaveToFile($hImageT, $outputImage) EndFunc Func ClearExtraArcLine($hGraphicT) ;Hide tail Local $fAngleT=$fAngle-$fAngle Local $iRadius = ($CircleDiameter / 2) + 1 Local $Deg = $fAngleT Local $R = ($nPI / 2) - ($Deg * ($nPI / 180)) Local $iX1 = $iCenter + Cos($R) * $iRadius Local $iY1 = $iCenter - Sin($R) * $iRadius Local $hPenT = _GDIPlus_PenCreate(0xFF00FF00, 26) _GDIPlus_GraphicsDrawLine($hGraphicT, $iCenter, $iCenter, $iX1, $iY1, $hPenT) EndFunc Thanks all!!!!!!!!! Edited October 25, 2023 by NassauSky Link to comment Share on other sites More sharing options...
Andreik Posted October 25, 2023 Share Posted October 25, 2023 It's good that you got your answer. I am just concerned when I see hard coded values like +/- 110. Maybe you can calculate these values with respect to your bitmap/bubble size but if these won't change in different context then never mind, use them as they are. NassauSky 1 When the words fail... music speaks. Link to comment Share on other sites More sharing options...
NassauSky Posted October 26, 2023 Author Share Posted October 26, 2023 (edited) Thanks @Andreik , Updated code with adding text using ideas from your font technique: I don't think I'm going much further with this unless someone has clarity on some parts that might not be the best way of handling the layers or displaying. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPIHObj.au3> ; For _GDIPlus_MatrixCreate Opt('MustDeclareVars', 1) _Main() Func _Main() Local $aCanvas, $hImage, $hGraphic Global $hGUI, $hWnd, $idButton, $cPic Global $outputImage = "SpeechBubble.png" Global Const $nPI = 3.1415926535897932384626433832795 Global $fAngle = 0 Global $nImgWidth = 220 Global $CircleDiameter = 150 Global $iCenter = $nImgWidth / 2 FileDelete($outputImage) ; Create GUI $hGUI = GUICreate("GDI+", $nImgWidth, $nImgWidth+20) ; 20 pixels for button height otherwise it's a square pic ctrl $idButton = GUICtrlCreateButton("Angle", 0, 0, 100, 20) ;$cPic = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) $cPic = CreatePictureControl() $hWnd = WinGetHandle("GDI+") GUISetState() ; Create a blank image _GDIPlus_Startup() $aCanvas = CreateGraphicContext() $hImage = $aCanvas[0] $hGraphic = $aCanvas[1] ; Create fill brushes and draw pens Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00) ; Light green color Local $hBrush2 = _GDIPlus_BrushCreateSolid(0xFF0000FF) ; Light blue color Global $hPen = _GDIPlus_PenCreate(0xFF8800AA, 2) Global $hPen2 = _GDIPlus_PenCreate(0xFFFF0000, 2) DrawTriangle($hGraphic, $hBrush, $hPen) DrawCircle($hGraphic, $hBrush, $hPen) ClearExtraArcLine($hGraphic) BitmapToCtrl($hImage, $cPic) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton Global $fAngle = InputBox( "Enter Angle", "Please enter the angle of the speech bubble pointer", 45) ConsoleWrite("Required Angle: " & $fAngle & @CRLF) SpeechBubbleRedraw($hGraphic, $hImage, $hBrush, $hPen) EndSwitch Until False ;GUIGetMsg() = $GUI_EVENT_CLOSE ; Save the image to $outputImage ;_GDIPlus_ImageSaveToFile($hImage, $outputImage) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_BitmapDispose($hImage) _GDIPlus_Shutdown() If FileExists($outputImage) Then ShellExecute($outputImage) EndFunc ;==>_Main Func BitmapToCtrl($hBitmap, $cCtrl) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_DeleteObject(GUICtrlSendMsg($cCtrl, 0x0172, 0, $hHBITMAP)) _WinAPI_DeleteObject($hHBITMAP) EndFunc Func CreatePictureControl() GUICtrlDelete($cPic) Local $cPicT = GUICtrlCreatePic('', 0, 20, $nImgWidth, $nImgWidth) GUISetState() Return $cPicT EndFunc Func CreateGraphicContext() Local $hImageT = _GDIPlus_BitmapCreateFromScan0($nImgWidth, $nImgWidth) Local $hGraphicT = _GDIPlus_ImageGetGraphicsContext($hImageT) Local $aCanvas[2] $aCanvas[0]=$hImageT $aCanvas[1]=$hGraphicT Return $aCanvas EndFunc Func DrawTriangle($hGraphicT, $hBrushT, $hPenT) Global $tWidth = $nImgWidth Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = $iCenter - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphicT, $aPoints, $hBrushT) _GDIPlus_GraphicsDrawPolygon($hGraphicT, $aPoints, $hPenT) EndFunc Func DrawCircle($hGraphicT, $hBrushT, $hPenT) Local $CircleX = ($nImgWidth - $CircleDiameter) / 2 Local $CircleY = ($nImgWidth - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrushT ) _GDIPlus_GraphicsDrawEllipse ( $hGraphicT, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPenT ) EndFunc Func SpeechBubbleRedraw($hGraphicT, $hImageT, $hBrushT, $hPenT) ; Create a matrix and rotate the image by $fAngle degrees _GDIPlus_GraphicsClear($hGraphicT, 0x00FFFFFF) ; Clear with white (0xFFFFFFFF) or any other desired color Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, +$iCenter, +$iCenter) _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_MatrixTranslate($hMatrix, -$iCenter, -$iCenter) _GDIPlus_GraphicsSetTransform($hGraphicT, $hMatrix) DrawTriangle($hGraphicT, $hBrushT, $hPenT) DrawCircle($hGraphicT, $hBrushT, $hPenT) ClearExtraArcLine($hGraphicT) CreatePictureControl() BitmapToCtrl($hImageT, $cPic) ; _GDIPlus_ImageSaveToFile($hImageT, $outputImage) Local $aCanvas2 = CreateGraphicContext() Local $hImage2 = $aCanvas2[0] Local $hGraphic2 = $aCanvas2[1] ; Draw text on top of the speech bubble Local $iTextColor = 0xFFFFFFFF, $sFontFamily = 'Arial', $iFontSize = 15, $iBubbleColor = 0xFF1D3557 Local $sString = "Fill In This Field" ; This is a test of a speech bubble to see how much text will fit inside." Local $hFamily = _GDIPlus_FontFamilyCreate($sFontFamily) Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize) Local $hFormat = _GDIPlus_StringFormatCreate() Local $hTextBrush = _GDIPlus_BrushCreateSolid($iBubbleColor) Local $tLayout = _GDIPlus_RectFCreate(47, 60, $iCenter+15, $iCenter) ; 47 & 60 best estimation (maybe a formula exists) Local $hPath = _GDIPlus_PathCreate(1) _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) _GDIPlus_GraphicsSetSmoothingMode($hGraphic2, 2) _GDIPlus_GraphicsDrawStringEx($hGraphic2, $sString, $hFont, $tLayout, $hFormat, $hTextBrush) _GDIPlus_BrushDispose($hTextBrush) _GDIPlus_FontDispose($hFont) BitmapToCtrl($hImage2, $cPic) ; Combine both bitmaps into a single one Local $aCanvas3 = CreateGraphicContext() Local $hImage3 = $aCanvas3[0] Local $hGraphic3 = $aCanvas3[1] Local $iWidth = _GDIPlus_ImageGetWidth($hImageT) Local $iHeight = _GDIPlus_ImageGetHeight($hImageT) Local $hMergedImage = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphic3) Local $hMergedGraphics = _GDIPlus_ImageGetGraphicsContext($hMergedImage) _GDIPlus_GraphicsDrawImageRect($hMergedGraphics, $hImageT, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDrawImageRect($hMergedGraphics, $hImage2, 0, 0, $iWidth, $iHeight) ; Save the combined image _GDIPlus_ImageSaveToFile($hMergedImage, $outputImage) ; Clean up resources _GDIPlus_GraphicsDispose($hMergedGraphics) _GDIPlus_BitmapDispose($hMergedImage) EndFunc Func ClearExtraArcLine($hGraphicT) ;Hide tail Local $fAngleT=$fAngle-$fAngle Local $iRadius = ($CircleDiameter / 2) + 1 Local $Deg = $fAngleT Local $R = ($nPI / 2) - ($Deg * ($nPI / 180)) Local $iX1 = $iCenter + Cos($R) * $iRadius Local $iY1 = $iCenter - Sin($R) * $iRadius Local $hPenT = _GDIPlus_PenCreate(0xFF00FF00, 26) ; Not sure why 26 and it's significance _GDIPlus_GraphicsDrawLine($hGraphicT, $iCenter, $iCenter, $iX1, $iY1, $hPenT) EndFunc Edited October 26, 2023 by NassauSky Link to comment Share on other sites More sharing options...
Andreik Posted October 26, 2023 Share Posted October 26, 2023 Not a big deal but usually you don't create a bunch of brushes and pens without a proper reason. You can create one of each and just change the color before you draw specific things. When the words fail... music speaks. Link to comment Share on other sites More sharing options...
Nine Posted October 26, 2023 Share Posted October 26, 2023 Here my 2 cents. I liked @ioa747 approach, much simpler not to rotate. expandcollapse popup#include <GDIPlus.au3> #include <GUIConstants.au3> #include <Math.au3> #include <WinAPISysWin.au3> ; bubble speech - radian Opt("MustDeclareVars", True) Global Const $SIZE = 250, $CENTER = $SIZE / 2, $DIAMETER = 200, $RADIUS = $DIAMETER / 2, $BORDER = 25 DrawBubble(45, 300, 300, 8, 25, "Hello World !" & @CR & "This is " & @ComputerName) Func DrawBubble($iDegree, $iPosX, $iPosY, $iWidth, $iHeight, $sText) _GDIPlus_Startup() Local $hGUI = GUICreate("Bubble", $SIZE, $SIZE, $iPosX, $iPosY, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) GUISetBkColor(0xBADBEE) _WinAPI_SetLayeredWindowAttributes($hGUI, 0xBADBEE) GUISetState(@SW_SHOW) Local $hPen = _GDIPlus_PenCreate(0xFF000000, 3) Local $hPenT = _GDIPlus_PenCreate(0xFFEE3333, 4) Local $hBrush = _GDIPlus_BrushCreateSolid(0xFFEE3333) Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsSetSmoothingMode($hGraphic, $GDIP_SMOOTHINGMODE_HIGHQUALITY) _GDIPlus_GraphicsFillEllipse($hGraphic, $BORDER, $BORDER, $DIAMETER, $DIAMETER, $hBrush) _GDIPlus_GraphicsDrawEllipse($hGraphic, $BORDER, $BORDER, $DIAMETER, $DIAMETER, $hPen) Local $aPoints[4][2] = [[3]], $iRadian $iRadian = _Radian(Mod(450 - $iDegree, 360)) $aPoints[1][0] = $CENTER + (($RADIUS + $iHeight) * Cos($iRadian)) $aPoints[1][1] = $CENTER - (($RADIUS + $iHeight) * Sin($iRadian)) $iRadian = _Radian(Mod(450 - $iDegree - $iWidth, 360)) $aPoints[2][0] = $CENTER + ($RADIUS * Cos($iRadian)) $aPoints[2][1] = $CENTER - ($RADIUS * Sin($iRadian)) $iRadian = _Radian(Mod(450 - $iDegree + $iWidth, 360)) $aPoints[3][0] = $CENTER + ($RADIUS * Cos($iRadian)) $aPoints[3][1] = $CENTER - ($RADIUS * Sin($iRadian)) _GDIPlus_GraphicsFillPolygon($hGraphic, $aPoints, $hBrush) _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints, $hPen) _GDIPlus_GraphicsDrawLine($hGraphic, $aPoints[2][0], $aPoints[2][1], $aPoints[3][0], $aPoints[3][1], $hPenT) AddText($hGraphic, $sText) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE _GDIPlus_BrushDispose($hBrush) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPenT) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() EndFunc ;==>DrawBubble Func AddText($hGraphic, $sText, $sFontName = "Comic Sans MS", $fSize = 14, $iColor = 0xFFFFFFFF) Local $hBrush = _GDIPlus_BrushCreateSolid($iColor), $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) ;center text horizontally + vertically _GDIPlus_StringFormatSetLineAlign($hFormat, 1) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName), $hFont = _GDIPlus_FontCreate($hFamily, $fSize) ; calculate string rectangle Local $iRadian = _Radian(135) ; -45° Local $iLeft = $CENTER + ($RADIUS * Cos($iRadian)) Local $iTop = $CENTER - ($RADIUS * Sin($iRadian)) $iRadian = _Radian(315) ; +135° Local $iWidth = $CENTER + ($RADIUS * Cos($iRadian)) - $iLeft Local $iHeight = $CENTER - ($RADIUS * Sin($iRadian)) - $iTop Local $tLayout = _GDIPlus_RectFCreate($iLeft, $iTop, $iWidth, $iHeight) _GDIPlus_GraphicsDrawStringEx($hGraphic, $sText, $hFont, $tLayout, $hFormat, $hBrush) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) EndFunc ;==>AddText NassauSky 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
NassauSky Posted October 27, 2023 Author Share Posted October 27, 2023 That is great @Nine. I think I can also use something like this without saving the output to file. I just modified it a little to shrink the bubble for my purposes of pointing to small items on the screen. Also added some code so the font direction doesn't follow the rotation of the bubble and marked up some code. I also changed the smoothing mode since on my screen it looked better with smoothing mode not applied but left the line in case anyone else wants to adjust it accordingly. expandcollapse popup#include <GDIPlus.au3> #include <GUIConstants.au3> #include <Math.au3> #include <WinAPISysWin.au3> Opt("MustDeclareVars", True) Global Const $SIZE = 220, $CENTER = $SIZE / 2, $DIAMETER = 150, $RADIUS = $DIAMETER / 2, $BORDER = 25 Local $fAngle = InputBox("Enter Angle","Please enter tail angle", 45) DrawBubble($fAngle, 300, 300, 8, 25, "Click the mystery database here.") Func DrawBubble($iDegree, $iPosX, $iPosY, $iWidth, $iHeight, $sText) _GDIPlus_Startup() ;-- Create GUI Transparent Local $hGUI = GUICreate("Bubble", $SIZE, $SIZE, $iPosX, $iPosY, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) GUISetBkColor(0xBADBEE) _WinAPI_SetLayeredWindowAttributes($hGUI, 0xBADBEE) GUISetState(@SW_SHOW) ;-- Setup Pens/Brushes ( Local $hPen = _GDIPlus_PenCreate(0xFF000000, 3) ; Triangle and Circle Border Local $hPenX = _GDIPlus_PenCreate(0xFFEE3333, 26) ; Hide Extra Tail Line Local $hBrush = _GDIPlus_BrushCreateSolid(0xFFEE3333) ;-- Setup Canvas to Draw on GUI Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;_GDIPlus_GraphicsSetSmoothingMode($hGraphic, 0) ; $GDIP_SMOOTHINGMODE_HIGHQUALITY) ;-- Rotate Canvas From Input Local Const $nPI = 3.1415926535897932384626433832795 Local $fAngle = $iDegree Local $nImgWidth = 220 Local $iCenter = $nImgWidth / 2 Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, +$iCenter, +$iCenter) _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_MatrixTranslate($hMatrix, -$iCenter, -$iCenter) _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) ;-- Create Triangle Global $tWidth = $nImgWidth Global $tHeight = 150 Global $TriangleBase = 60 Global $TriangleHeight = 60 Global $TriangleX = $iCenter - $TriangleBase / 2 Global $TriangleY = 65 ; $CircleY + $CircleDiameter / 2 Local $aPoints[4][2] ; Create Points Array (Row 0 Col 0 holds row count) $aPoints[0][0] = 3 ;Number of points $aPoints[1][0] = $TriangleX $aPoints[1][1] = $TriangleY $aPoints[2][0] = $TriangleX + $TriangleBase $aPoints[2][1] = $TriangleY $aPoints[3][0] = $TriangleX + $TriangleBase / 2 $aPoints[3][1] = $TriangleY - $TriangleHeight _GDIPlus_GraphicsFillPolygon($hGraphic, $aPoints, $hBrush) _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints, $hPen) ;-- Create Circle Local $CircleDiameter = 150 Local $CircleX = ($nImgWidth - $CircleDiameter) / 2 Local $CircleY = ($nImgWidth - $CircleDiameter) / 2 _GDIPlus_GraphicsFillEllipse ( $hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hBrush ) _GDIPlus_GraphicsDrawEllipse ( $hGraphic, $CircleX, $CircleY, $CircleDiameter, $CircleDiameter, $hPen ) ;-- Hide Extra Tail Line Local $fAngleT=$fAngle-$fAngle Local $iRadius = ($CircleDiameter / 2) + 1 Local $Deg = $fAngleT Local $R = ($nPI / 2) - ($Deg * ($nPI / 180)) Local $iX1 = $iCenter + Cos($R) * $iRadius + 1 Local $iY1 = $iCenter - Sin($R) * $iRadius - 1 _GDIPlus_GraphicsDrawLine($hGraphic, $iCenter, $iCenter, $iX1, $iY1, $hPenX) AddText($hGraphic, $sText , 0) ; 0=Do not have text follow the tails rotation angle Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ;--Cleanup _GDIPlus_BrushDispose($hBrush) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPenX) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() EndFunc ;==>DrawBubble Func AddText($hGraphic, $sText, $iDegree = 0, $sFontName = "Comic Sans MS", $fSize = 14, $iColor = 0xFFFFFFFF) ;-- Rotate Canvas From Input Local Const $nPI = 3.1415926535897932384626433832795 Local $fAngle = $iDegree Local $nImgWidth = 220 Local $CircleDiameter = 150 Local $iCenter = $nImgWidth / 2 Local $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, +$iCenter, +$iCenter) _GDIPlus_MatrixRotate($hMatrix, $fAngle, "False") _GDIPlus_MatrixTranslate($hMatrix, -$iCenter, -$iCenter) _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix) ;-- Setup Font Characteristics Local $hBrush = _GDIPlus_BrushCreateSolid($iColor) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName) Local $hFont = _GDIPlus_FontCreate($hFamily, $fSize) Local $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) ; Center text horizontally + vertically _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ;-- Create String Rectangle Boundary Local $iRadian = _Radian(135) ; -45° Local $iLeft = $CENTER + ($RADIUS * Cos($iRadian)) Local $iTop = $CENTER - ($RADIUS * Sin($iRadian)) $iRadian = _Radian(315) ; +135° Local $iWidth = $CENTER + ($RADIUS * Cos($iRadian)) - $iLeft Local $iHeight = $CENTER - ($RADIUS * Sin($iRadian)) - $iTop Local $tLayout = _GDIPlus_RectFCreate($iLeft, $iTop, $iWidth, $iHeight) ;-- Draw String Inside Rectangle Boundary _GDIPlus_GraphicsDrawStringEx($hGraphic, $sText, $hFont, $tLayout, $hFormat, $hBrush) ;-- Cleanup _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) EndFunc ;==>AddText Link to comment Share on other sites More sharing options...
UEZ Posted October 27, 2023 Share Posted October 27, 2023 (edited) Here my simple version of a speech bubble: expandcollapse popup#include <GDIPlus.au3> _GDIPlus_Startup() Global $iW = 600 Global $iH = 600 Global $hGUI = GUICreate("Test", $iW, $iH) GUISetBkColor(0x808080) GUISetState() _GDIPlus_Startup() Global $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsSetSmoothingMode($hGraphic, $GDIP_SMOOTHINGMODE_HIGHQUALITY) _GDIPlus_GraphicsSetTextRenderingHint($hGraphic, $GDIP_TEXTRENDERINGHINTANTIALIAS) _GDIPlus_DrawSpeechBubble($hGraphic, "Blah blah blah" & @CRLF & "blah blah!", 40, -20, 4, 3, 100, "Comic Sans MS", 7, 0xFF000000, 14, 0xFFFFFFFF, 0xFFFF00FF, 0xFF000000, 2, 100, 100) Do Until GUIGetMsg() = -3 _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() Exit ;code by UEZ build 2023-10-27 Func _GDIPlus_DrawSpeechBubble($hGraphic, $sString, $fFontSize = 12, $fAngle = -20, $fScaleX = 1.0, $fScaleY = 1.0, $fSize = 100, $sFontname = "Arial", $fLegSize = 7, $iLineColor = 0xFF000000, $fPenSize = 2, _ $iFillColor = 0xFFFFFFFF, $iTxtColor = 0xFF000000, $iTxtBorderColor = $iTxtColor, $fPenSizeBorder = 1, $fXOffset = $fPenSize / 2, $fYOffset = $fPenSize / 2) Local Const $hPath = _GDIPlus_PathCreate(), $hMatrix = _GDIPlus_MatrixCreate(), $hPen = _GDIPlus_PenCreate($iLineColor, $fPenSize), $hBrush = _GDIPlus_BrushCreateSolid($iFillColor), _ $hBrush_txt = _GDIPlus_BrushCreateSolid($iTxtColor), $hPen_txt = _GDIPlus_PenCreate($iTxtBorderColor, $fPenSizeBorder), _ $hFamily = _GDIPlus_FontFamilyCreate($sFontname), $hFormat = _GDIPlus_StringFormatCreate(), $hFont = _GDIPlus_FontCreate($hFamily, $fFontSize, 0) _GDIPlus_PathAddEllipse($hPath, 1, 1, $fSize, $fSize) _GDIPlus_PathAddEllipse($hPath, $fSize / 2 - $fLegSize, $fSize - $fSize / 4, $fLegSize, $fSize / 2) _GDIPlus_PathWindingModeOutline($hPath, 0, 0.1) _GDIPlus_MatrixTranslate($hMatrix, $fSize / 2, $fSize / 2) _GDIPlus_MatrixRotate($hMatrix, $fAngle) _GDIPlus_MatrixTranslate($hMatrix, -$fSize / 2, -$fSize / 2) _GDIPlus_PathTransform($hPath, $hMatrix) _GDIPlus_MatrixSetElements($hMatrix, 1, 0, 0, 1, 0, 0) ;reset matrix _GDIPlus_MatrixScale($hMatrix, $fScaleX, $fScaleY) _GDIPlus_PathTransform($hPath, $hMatrix) _GDIPlus_MatrixSetElements($hMatrix, 1, 0, 0, 1, 0, 0) ;reset matrix _GDIPlus_MatrixTranslate($hMatrix, $fXOffset, $fYOffset) _GDIPlus_PathTransform($hPath, $hMatrix) _GDIPlus_GraphicsDrawPath($hGraphic, $hPath, $hPen) _GDIPlus_GraphicsFillPath($hGraphic, $hPath, $hBrush) _GDIPlus_PathReset($hPath) _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) Local $tLayout = _GDIPlus_RectFCreate($fXOffset, $fYOffset, $fSize * $fScaleX, $fSize * $fScaleY) _GDIPlus_PathAddString($hPath, $sString, $tLayout, $hFamily, 0, $fFontSize, $hFormat) _GDIPlus_GraphicsFillPath($hGraphic, $hPath, $hBrush_txt) _GDIPlus_GraphicsDrawPath($hGraphic, $hPath, $hPen_txt) ;_GDIPlus_GraphicsDrawStringEx($hGraphic, $sString, $hFont, $tLayout, $hFormat, $hBrush_txt) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_PathDispose($hPath) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPen_txt) _GDIPlus_MatrixDispose($hMatrix) _GDIPlus_BrushDispose($hBrush) _GDIPlus_BrushDispose($hBrush_txt) EndFunc Edited October 27, 2023 by UEZ NassauSky 1 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now