SVG to IMG ohne externe Komponente

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

      SVG to IMG ohne externe Komponente

      Hallo Leute,

      ich hatte letztes Jahr bei der Erstellung einer Windows APP die Herausforderung Vektrografiken im SVG Format in ein Grafikformat zu bringen oder am Bildschirm anzeigen zu lassen.
      Gestern hatte sich mein Knoten gelöst und durch einen Tipp im Netz habe ich nun endlich eine Lösung gefunden für die keine externe Komponente erforderlich ist.

      Man benötigt lediglich ein Webbrowser-Control WebBrowser_SVG und eine Picturebox PictureBox_SVG.
      Grob erklärt wird die SVG-Datei im Webbrowser-Control angezeigt und dann dort über eine Art Handle (iViewObject) als Grafik abgegriffen und in die Picturebox kopiert.
      Genauer wird dies in den Microsoft-Docs beschrieben: docs.microsoft.com/en-us/windo…idl/nn-oleidl-iviewobject

      Die Grafik in der Picturebox kann man dann beliebig weiterbearbeiten (z.B. speichern).
      Bzw. könnte man die Picturebox auch ganz weglassen und bereits mit der erzeugten Bitmap bmp weiterarbeiten

      Das Webbrowser-Control muss immer in die Größe der gewünschten Zielgrafik gebracht werden. Das sieht in einer Form nicht schön aus.
      Man kann das Webbrowser-Control aber auch außerhalb der sichtbaren Form darstellen - der Grafikinhalt wird dennoch ausgelesen.

      Hier mein Code einer Windows-Forms-Anwendung

      VB.NET-Quellcode

      1. Imports System.Runtime.InteropServices
      2. Public Class FRM_Mainform
      3. <ComImport()>
      4. <Guid("0000010d-0000-0000-C000-000000000046")>
      5. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
      6. Public Interface IViewObject
      7. <PreserveSig>
      8. Function Draw(dwDrawAspect As UInteger, lindex As Integer, pvAspect As IntPtr, ptd As IntPtr, hdcTargetDev As IntPtr, hdcDraw As IntPtr, lprcBounds As Rectangle, lprcWBounds As IntPtr, pfnContinue As IntPtr, dwContinue As Integer) As Integer
      9. End Interface
      10. Private Sub FRM_Mainform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      11. WebBrowser_SVG.Width = 1000 'gewünschte Pixelbreite der zu erzeugenden Grafik
      12. WebBrowser_SVG.Height = 2000 'gewünschte Pixelhöhe der zu erzeugenden Grafik
      13. WebBrowser_SVG.ScrollBarsEnabled = False
      14. WebBrowser_SVG.Url = New Uri(String.Format("c:\Testgrafik.svg"))
      15. End Sub
      16. Private Sub WebBrowserSVG_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser_SVG.DocumentCompleted
      17. Dim nWidth = WebBrowser_SVG.Width
      18. Dim nHeight = WebBrowser_SVG.Height
      19. Dim bmp = New Bitmap(nWidth, nHeight)
      20. Dim gr As Graphics = Graphics.FromImage(bmp)
      21. Dim hDC = gr.GetHdc()
      22. Dim rc = New Rectangle(0, 0, nWidth, nHeight)
      23. Dim viewObject = CType(WebBrowser_SVG.Document.DomDocument, IViewObject)
      24. viewObject.Draw(CUInt(DVASPECT.DVASPECT_CONTENT), -1, CType(0, IntPtr), CType(0, IntPtr), CType(0, IntPtr), hDC, rc, CType(0, IntPtr), CType(0, IntPtr), 0)
      25. gr.ReleaseHdc(hDC)
      26. 'Optional die Bitmap in eine PictureBox kopieren oder direkt weiterverarbeiten
      27. PictureBox_SVG.Image = bmp
      28. PictureBox_SVG.Image.Save("c:/SVGAlsGrafik.jpg")
      29. End Sub
      30. End Class


      Hier eine SVG Grafik und das daraus erstelle JPG Image.
      Die SVG Grafik enthält neben Vektroinformationen zusätzlich auch eine BMP-Background-Image.
      Bilder
      • 1.jpg

        129,05 kB, 1.404×1.872, 97 mal angesehen
      Dateien
      • svgdatei.zip

        (260,4 kB, 56 mal heruntergeladen, zuletzt: )
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
      Hi

      SVG-Bilder kann man auch per Direct2D über das Interface ID2D1DeviceContext5::CreateSvgDocument von einem IStream (von einer SVG-Datei zB.) laden und per ID2D1DeviceContext5::DrawSvgDocument in einen RenderTarget, zb von einm IWICBitmap, von einem DC oder HWND, zeichnen. Das IWICBitmap könnte man dann zb als JPG, PNG (bzw alle von WIC unterstützte Bildformate die gespeichert werden können) gespeichert werden. Alternativ kann man auch vom IWICBitmap sich die Pixeldaten holen (ähnlich LockBits/UnlockBits) und diese in ein GDI+-Bitmap übertragen. Erspart einem das WebBrowser-Control auf der Form.
      Mfg -Franky-

      AKP schrieb:

      Das scheint soweit ganz gut zu klappen.
      Wie siehts denn aus wenn ich z.B. dies hier:
      bnj.blob.core.windows.net/asse…es/Theme/rfj/logo-rfj.svg
      in einer Picturebox mit 75 x 75 Pixel haben will? Das Webbrowsersteuerelement würde hier Scrollbars anzeigen.



      Dann einfach vorher im. Webbrowser Control die Scrollnars disabeln
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
      Hi

      Hier mal ein einfaches Sample das zeigt, wie man grundsätzlich ein SVG per Direct2D lädt, das auf ein hWnd gerendert wird. Ja, ist viel Code, ich weis. ;)
      Spoiler anzeigen

      Quellcode

      1. Option Strict On
      2. Option Explicit On
      3. Imports System.IO
      4. Imports System.Runtime.InteropServices
      5. Module modSVG
      6. #Region "Const"
      7. Private Const S_OK As Integer = 0
      8. Private Const D3D_FEATURE_LEVEL_9_1 As Integer = 37120
      9. Private Const D3D_FEATURE_LEVEL_10_0 As Integer = 40960
      10. Private Const IID_ID2D1Factory As String = "06152247-6f50-465a-9245-118bfd3b6007"
      11. Private Const IID_ID2D1DeviceContext5 As String = "7836d248-68cc-4df6-b9e8-de991bf62eb7"
      12. #End Region
      13. #Region "Enums"
      14. Private Enum VTable_Interfaces As Integer
      15. '----==== ID2D1Factory ====----
      16. CreateHwndRenderTarget = 14
      17. '----==== ID2D1RenderTarget ====----
      18. Clear = 47
      19. BeginDraw = 48
      20. EndDraw = 49
      21. '----==== ID2D1HwndRenderTarget ====----
      22. Resize = 58
      23. '----==== ID2D1DeviceContext5 ====----
      24. CreateSvgDocument = 115
      25. DrawSvgDocument = 116
      26. End Enum
      27. Private Enum STGM As Integer
      28. STGM_FAILIFTHERE = &H0
      29. STGM_DIRECT = &H0
      30. STGM_READ = &H0
      31. STGM_WRITE = &H1
      32. STGM_READWRITE = &H2
      33. STGM_SHARE_EXCLUSIVE = &H10
      34. STGM_SHARE_DENY_WRITE = &H20
      35. STGM_SHARE_DENY_READ = &H30
      36. STGM_SHARE_DENY_NONE = &H40
      37. STGM_CREATE = &H1000
      38. STGM_TRANSACTED = &H10000
      39. STGM_CONVERT = &H20000
      40. STGM_PRIORITY = &H40000
      41. STGM_NOSCRATCH = &H100000
      42. STGM_NOSNAPSHOT = &H200000
      43. STGM_DIRECT_SWMR = &H400000
      44. STGM_SIMPLE = &H8000000
      45. STGM_DELETEONRELEASE = &H4000000
      46. End Enum
      47. Private Enum D2D1_FACTORY_TYPE As Integer
      48. D2D1_FACTORY_TYPE_SINGLE_THREADED = 0
      49. D2D1_FACTORY_TYPE_MULTI_THREADED = 1
      50. End Enum
      51. Private Enum D2D1_DEBUG_LEVEL As Integer
      52. D2D1_DEBUG_LEVEL_NONE = 0
      53. D2D1_DEBUG_LEVEL_ERROR = 1
      54. D2D1_DEBUG_LEVEL_WARNING = 2
      55. D2D1_DEBUG_LEVEL_INFORMATION = 3
      56. End Enum
      57. Private Enum D2D1_RENDER_TARGET_TYPE As Integer
      58. D2D1_RENDER_TARGET_TYPE_DEFAULT = 0
      59. D2D1_RENDER_TARGET_TYPE_SOFTWARE = 1
      60. D2D1_RENDER_TARGET_TYPE_HARDWARE = 2
      61. End Enum
      62. Private Enum D2D1_RENDER_TARGET_USAGE As Integer
      63. D2D1_RENDER_TARGET_USAGE_NONE = 0
      64. D2D1_RENDER_TARGET_USAGE_FORCE_BITMAP_REMOTING = 1
      65. D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE = 2
      66. End Enum
      67. Private Enum D2D1_FEATURE_LEVEL As Integer
      68. D2D1_FEATURE_LEVEL_DEFAULT = 0
      69. D2D1_FEATURE_LEVEL_9 = D3D_FEATURE_LEVEL_9_1
      70. D2D1_FEATURE_LEVEL_10 = D3D_FEATURE_LEVEL_10_0
      71. End Enum
      72. Private Enum D2D1_ALPHA_MODE As Integer
      73. D2D1_ALPHA_MODE_UNKNOWN = 0
      74. D2D1_ALPHA_MODE_PREMULTIPLIED = 1
      75. D2D1_ALPHA_MODE_STRAIGHT = 2
      76. D2D1_ALPHA_MODE_IGNORE = 3
      77. End Enum
      78. Private Enum D2D1_PRESENT_OPTIONS As Integer
      79. D2D1_PRESENT_OPTIONS_NONE = 0
      80. D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS = 1
      81. D2D1_PRESENT_OPTIONS_IMMEDIATELY = 2
      82. End Enum
      83. Private Enum D2D1_SVG_ATTRIBUTE_STRING_TYPE As Integer
      84. D2D1_SVG_ATTRIBUTE_STRING_TYPE_SVG = 0
      85. D2D1_SVG_ATTRIBUTE_STRING_TYPE_ID = 1
      86. End Enum
      87. Private Enum D2D1_SVG_ATTRIBUTE_POD_TYPE As Integer
      88. D2D1_SVG_ATTRIBUTE_POD_TYPE_FLOAT = 0
      89. D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR = 1
      90. D2D1_SVG_ATTRIBUTE_POD_TYPE_FILL_MODE = 2
      91. D2D1_SVG_ATTRIBUTE_POD_TYPE_DISPLAY = 3
      92. D2D1_SVG_ATTRIBUTE_POD_TYPE_OVERFLOW = 4
      93. D2D1_SVG_ATTRIBUTE_POD_TYPE_LINE_CAP = 5
      94. D2D1_SVG_ATTRIBUTE_POD_TYPE_LINE_JOIN = 6
      95. D2D1_SVG_ATTRIBUTE_POD_TYPE_VISIBILITY = 7
      96. D2D1_SVG_ATTRIBUTE_POD_TYPE_MATRIX = 8
      97. D2D1_SVG_ATTRIBUTE_POD_TYPE_UNIT_TYPE = 9
      98. D2D1_SVG_ATTRIBUTE_POD_TYPE_EXTEND_MODE = 10
      99. D2D1_SVG_ATTRIBUTE_POD_TYPE_PRESERVE_ASPECT_RATIO = 11
      100. D2D1_SVG_ATTRIBUTE_POD_TYPE_VIEWBOX = 12
      101. D2D1_SVG_ATTRIBUTE_POD_TYPE_LENGTH = 13
      102. End Enum
      103. Private Enum DXGI_FORMAT As Integer
      104. DXGI_FORMAT_UNKNOWN = 0
      105. DXGI_FORMAT_R32G32B32A32_TYPELESS = 1
      106. DXGI_FORMAT_R32G32B32A32_FLOAT = 2
      107. DXGI_FORMAT_R32G32B32A32_UINT = 3
      108. DXGI_FORMAT_R32G32B32A32_SINT = 4
      109. DXGI_FORMAT_R32G32B32_TYPELESS = 5
      110. DXGI_FORMAT_R32G32B32_FLOAT = 6
      111. DXGI_FORMAT_R32G32B32_UINT = 7
      112. DXGI_FORMAT_R32G32B32_SINT = 8
      113. DXGI_FORMAT_R16G16B16A16_TYPELESS = 9
      114. DXGI_FORMAT_R16G16B16A16_FLOAT = 10
      115. DXGI_FORMAT_R16G16B16A16_UNORM = 11
      116. DXGI_FORMAT_R16G16B16A16_UINT = 12
      117. DXGI_FORMAT_R16G16B16A16_SNORM = 13
      118. DXGI_FORMAT_R16G16B16A16_SINT = 14
      119. DXGI_FORMAT_R32G32_TYPELESS = 15
      120. DXGI_FORMAT_R32G32_FLOAT = 16
      121. DXGI_FORMAT_R32G32_UINT = 17
      122. DXGI_FORMAT_R32G32_SINT = 18
      123. DXGI_FORMAT_R32G8X24_TYPELESS = 19
      124. DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20
      125. DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21
      126. DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22
      127. DXGI_FORMAT_R10G10B10A2_TYPELESS = 23
      128. DXGI_FORMAT_R10G10B10A2_UNORM = 24
      129. DXGI_FORMAT_R10G10B10A2_UINT = 25
      130. DXGI_FORMAT_R11G11B10_FLOAT = 26
      131. DXGI_FORMAT_R8G8B8A8_TYPELESS = 27
      132. DXGI_FORMAT_R8G8B8A8_UNORM = 28
      133. DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29
      134. DXGI_FORMAT_R8G8B8A8_UINT = 30
      135. DXGI_FORMAT_R8G8B8A8_SNORM = 31
      136. DXGI_FORMAT_R8G8B8A8_SINT = 32
      137. DXGI_FORMAT_R16G16_TYPELESS = 33
      138. DXGI_FORMAT_R16G16_FLOAT = 34
      139. DXGI_FORMAT_R16G16_UNORM = 35
      140. DXGI_FORMAT_R16G16_UINT = 36
      141. DXGI_FORMAT_R16G16_SNORM = 37
      142. DXGI_FORMAT_R16G16_SINT = 38
      143. DXGI_FORMAT_R32_TYPELESS = 39
      144. DXGI_FORMAT_D32_FLOAT = 40
      145. DXGI_FORMAT_R32_FLOAT = 41
      146. DXGI_FORMAT_R32_UINT = 42
      147. DXGI_FORMAT_R32_SINT = 43
      148. DXGI_FORMAT_R24G8_TYPELESS = 44
      149. DXGI_FORMAT_D24_UNORM_S8_UINT = 45
      150. DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46
      151. DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47
      152. DXGI_FORMAT_R8G8_TYPELESS = 48
      153. DXGI_FORMAT_R8G8_UNORM = 49
      154. DXGI_FORMAT_R8G8_UINT = 50
      155. DXGI_FORMAT_R8G8_SNORM = 51
      156. DXGI_FORMAT_R8G8_SINT = 52
      157. DXGI_FORMAT_R16_TYPELESS = 53
      158. DXGI_FORMAT_R16_FLOAT = 54
      159. DXGI_FORMAT_D16_UNORM = 55
      160. DXGI_FORMAT_R16_UNORM = 56
      161. DXGI_FORMAT_R16_UINT = 57
      162. DXGI_FORMAT_R16_SNORM = 58
      163. DXGI_FORMAT_R16_SINT = 59
      164. DXGI_FORMAT_R8_TYPELESS = 60
      165. DXGI_FORMAT_R8_UNORM = 61
      166. DXGI_FORMAT_R8_UINT = 62
      167. DXGI_FORMAT_R8_SNORM = 63
      168. DXGI_FORMAT_R8_SINT = 64
      169. DXGI_FORMAT_A8_UNORM = 65
      170. DXGI_FORMAT_R1_UNORM = 66
      171. DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67
      172. DXGI_FORMAT_R8G8_B8G8_UNORM = 68
      173. DXGI_FORMAT_G8R8_G8B8_UNORM = 69
      174. DXGI_FORMAT_BC1_TYPELESS = 70
      175. DXGI_FORMAT_BC1_UNORM = 71
      176. DXGI_FORMAT_BC1_UNORM_SRGB = 72
      177. DXGI_FORMAT_BC2_TYPELESS = 73
      178. DXGI_FORMAT_BC2_UNORM = 74
      179. DXGI_FORMAT_BC2_UNORM_SRGB = 75
      180. DXGI_FORMAT_BC3_TYPELESS = 76
      181. DXGI_FORMAT_BC3_UNORM = 77
      182. DXGI_FORMAT_BC3_UNORM_SRGB = 78
      183. DXGI_FORMAT_BC4_TYPELESS = 79
      184. DXGI_FORMAT_BC4_UNORM = 80
      185. DXGI_FORMAT_BC4_SNORM = 81
      186. DXGI_FORMAT_BC5_TYPELESS = 82
      187. DXGI_FORMAT_BC5_UNORM = 83
      188. DXGI_FORMAT_BC5_SNORM = 84
      189. DXGI_FORMAT_B5G6R5_UNORM = 85
      190. DXGI_FORMAT_B5G5R5A1_UNORM = 86
      191. DXGI_FORMAT_B8G8R8A8_UNORM = 87
      192. DXGI_FORMAT_B8G8R8X8_UNORM = 88
      193. DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89
      194. DXGI_FORMAT_B8G8R8A8_TYPELESS = 90
      195. DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91
      196. DXGI_FORMAT_B8G8R8X8_TYPELESS = 92
      197. DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93
      198. DXGI_FORMAT_BC6H_TYPELESS = 94
      199. DXGI_FORMAT_BC6H_UF16 = 95
      200. DXGI_FORMAT_BC6H_SF16 = 96
      201. DXGI_FORMAT_BC7_TYPELESS = 97
      202. DXGI_FORMAT_BC7_UNORM = 98
      203. DXGI_FORMAT_BC7_UNORM_SRGB = 99
      204. DXGI_FORMAT_AYUV = 100
      205. DXGI_FORMAT_Y410 = 101
      206. DXGI_FORMAT_Y416 = 102
      207. DXGI_FORMAT_NV12 = 103
      208. DXGI_FORMAT_P010 = 104
      209. DXGI_FORMAT_P016 = 105
      210. DXGI_FORMAT_420_OPAQUE = 106
      211. DXGI_FORMAT_YUY2 = 107
      212. DXGI_FORMAT_Y210 = 108
      213. DXGI_FORMAT_Y216 = 109
      214. DXGI_FORMAT_NV11 = 110
      215. DXGI_FORMAT_AI44 = 111
      216. DXGI_FORMAT_IA44 = 112
      217. DXGI_FORMAT_P8 = 113
      218. DXGI_FORMAT_A8P8 = 114
      219. DXGI_FORMAT_B4G4R4A4_UNORM = 115
      220. DXGI_FORMAT_P208 = 130
      221. DXGI_FORMAT_V208 = 131
      222. DXGI_FORMAT_V408 = 132
      223. End Enum
      224. #End Region
      225. #Region "Structures"
      226. Private Structure D2D1_FACTORY_OPTIONS
      227. Dim debugLevel As D2D1_DEBUG_LEVEL
      228. Sub New(Optional eDebugLevel As D2D1_DEBUG_LEVEL = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_NONE)
      229. debugLevel = eDebugLevel
      230. End Sub
      231. End Structure
      232. Private Structure D2D1_PIXEL_FORMAT
      233. Dim dFormat As DXGI_FORMAT
      234. Dim AlphaMode As D2D1_ALPHA_MODE
      235. Sub New(eAlphaMode As D2D1_ALPHA_MODE, eDXGIFormat As DXGI_FORMAT)
      236. AlphaMode = eAlphaMode
      237. dFormat = eDXGIFormat
      238. End Sub
      239. End Structure
      240. Private Structure D2D1_RENDER_TARGET_PROPERTIES
      241. Dim etype As D2D1_RENDER_TARGET_TYPE
      242. Dim PixelFormat As D2D1_PIXEL_FORMAT
      243. Dim DpiX As Single
      244. Dim DpiY As Single
      245. Dim Usage As D2D1_RENDER_TARGET_USAGE
      246. Dim minLevel As D2D1_FEATURE_LEVEL
      247. Sub New(tPixelFormat As D2D1_PIXEL_FORMAT)
      248. PixelFormat = tPixelFormat
      249. End Sub
      250. End Structure
      251. Private Structure D2D1_HWND_RENDER_TARGET_PROPERTIES
      252. Dim hwnd As IntPtr
      253. Dim pixelSize As D2D1_SIZE_U
      254. Dim presentOptions As D2D1_PRESENT_OPTIONS
      255. Sub New(pHwnd As IntPtr)
      256. hwnd = pHwnd
      257. End Sub
      258. End Structure
      259. Private Structure D2D1_SIZE_F
      260. Dim Width As Single
      261. Dim Height As Single
      262. Sub New(sngWidth As Single,
      263. sngHeight As Single)
      264. Width = sngWidth
      265. Height = sngHeight
      266. End Sub
      267. End Structure
      268. Public Structure D2D1_SIZE_U
      269. Dim Width As Integer
      270. Dim Height As Integer
      271. Sub New(intWidth As Integer,
      272. intHeight As Integer)
      273. Width = intWidth
      274. Height = intHeight
      275. End Sub
      276. End Structure
      277. Private Structure D2D1_COLOR_F
      278. Dim r As Single
      279. Dim g As Single
      280. Dim b As Single
      281. Dim a As Single
      282. Sub New(Optional sngA As Single = 1,
      283. Optional sngR As Single = 0,
      284. Optional sngG As Single = 0,
      285. Optional sngB As Single = 0)
      286. r = sngR
      287. g = sngG
      288. b = sngB
      289. a = sngA
      290. End Sub
      291. End Structure
      292. Private Structure D2D1_TAG
      293. Dim value As ULong
      294. End Structure
      295. #End Region
      296. #Region "APIs"
      297. <DllImport("shlwapi.dll", EntryPoint:="SHCreateStreamOnFileW")>
      298. <PreserveSig> Private Function SHCreateStreamOnFile(<[In]> <MarshalAs(UnmanagedType.LPWStr)> pszFile As String,
      299. <[In]> grfMode As STGM,
      300. <Out> ByRef ppIStm As IntPtr) As Integer
      301. End Function
      302. <DllImport("D2d1.dll", EntryPoint:="D2D1CreateFactory")>
      303. <PreserveSig> Private Function D2D1CreateFactory(<[In]> factoryType As D2D1_FACTORY_TYPE,
      304. <[In]> ByRef riid As Guid,
      305. <[In]> ByRef pFactoryOptions As D2D1_FACTORY_OPTIONS,
      306. <Out> ByRef ppIFactory As IntPtr) As Integer
      307. End Function
      308. #End Region
      309. #Region "Delegates"
      310. '----==== ID2D1Factory ====----
      311. Private Delegate Function ID2D1Factory_CreateHwndRenderTarget(<[In]> this As IntPtr,
      312. <[In]> ByRef renderTargetProperties As D2D1_RENDER_TARGET_PROPERTIES,
      313. <[In]> ByRef hwndRenderTargetProperties As D2D1_HWND_RENDER_TARGET_PROPERTIES,
      314. <Out> ByRef ppID2D1HwndRenderTarget As IntPtr) As Integer
      315. '----==== ID2D1RenderTarget ====----
      316. Private Delegate Sub ID2D1RenderTarget_Clear(<[In]> this As IntPtr,
      317. <[In]> ByRef color As D2D1_COLOR_F)
      318. Private Delegate Sub ID2D1RenderTarget_BeginDraw(<[In]> this As IntPtr)
      319. Private Delegate Function ID2D1RenderTarget_EndDraw(<[In]> this As IntPtr,
      320. <Out> ByRef tag1 As D2D1_TAG,
      321. <Out> ByRef tag2 As D2D1_TAG) As Integer
      322. '----==== ID2D1HwndRenderTarget ====----
      323. Private Delegate Function ID2D1HwndRenderTarget_Resize(<[In]> this As IntPtr,
      324. <[In]> ByRef pixelSize As D2D1_SIZE_U) As Integer
      325. '----==== ID2D1DeviceContext5 ====----
      326. Private Delegate Function ID2D1DeviceContext5_CreateSvgDocument(<[In]> this As IntPtr,
      327. <[In]> inputXmlStream As IntPtr,
      328. <[In]> viewportSize As D2D1_SIZE_F,
      329. <Out> ByRef svgDocument As IntPtr) As Integer
      330. Private Delegate Sub ID2D1DeviceContext5_DrawSvgDocument(<[In]> this As IntPtr,
      331. <[In]> svgDocument As IntPtr)
      332. #End Region
      333. #Region "Public Functions"
      334. Public Function LoadSVG(strSvgPath As String, oControl As Control) As Boolean
      335. Dim bolRet As Boolean = False
      336. Dim pIStream As IntPtr = IntPtr.Zero
      337. Dim pID2D1Factory As IntPtr = IntPtr.Zero
      338. Dim pID2D1RenderTarget As IntPtr = IntPtr.Zero
      339. Dim pID2D1DeviceContext5 As IntPtr = IntPtr.Zero
      340. Dim pID2D1SvgDocument As IntPtr = IntPtr.Zero
      341. ' existiert die Datei?
      342. If File.Exists(strSvgPath) Then
      343. ' Direct2D initialisieren
      344. If D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, New Guid(IID_ID2D1Factory),
      345. New D2D1_FACTORY_OPTIONS(D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_NONE),
      346. pID2D1Factory) = S_OK Then
      347. ' ein ID2D1HwndRenderTarget (ID2D1RenderTarget) erstellen <- Control.Handle
      348. If D2D1Factory_CreateHwndRenderTarget(pID2D1Factory,
      349. New D2D1_RENDER_TARGET_PROPERTIES(
      350. New D2D1_PIXEL_FORMAT(D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED,
      351. DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM)),
      352. New D2D1_HWND_RENDER_TARGET_PROPERTIES(oControl.Handle),
      353. pID2D1RenderTarget) Then
      354. ' ein ID2D1DeviceContext5 vom ID2D1HwndRenderTarget erstellen
      355. If Marshal.QueryInterface(pID2D1RenderTarget, New Guid(IID_ID2D1DeviceContext5), pID2D1DeviceContext5) = S_OK Then
      356. ' SVG in einen IStream laden
      357. If SHCreateStreamOnFile(strSvgPath, STGM.STGM_READ Or STGM.STGM_SHARE_DENY_WRITE, pIStream) = S_OK Then
      358. ' vom IStream ein ID2D1SvgDocument erstellen
      359. If D2D1DeviceContext5_CreateSvgDocument(pID2D1DeviceContext5, pIStream, New D2D1_SIZE_F(1, 1), pID2D1SvgDocument) Then
      360. ' mit dem ID2D1SvgDocument hätte man Zugriff auf die komplette SVG
      361. ' und könnte diese darüber manipulieren / verändern / bearbeiten usw.
      362. ' Größe des ID2D1HwndRenderTarget festlegen
      363. If D2D1HwndRenderTarget_Resize(pID2D1RenderTarget, New D2D1_SIZE_U(oControl.Width, oControl.Height)) Then
      364. ' mit dem zeichnen in den ID2D1HwndRenderTarget beginnen
      365. D2D1RenderTarget_BeginDraw(pID2D1RenderTarget)
      366. ' Hintergrundfarbe für den ID2D1HwndRenderTarget festlegen
      367. D2D1RenderTarget_Clear(pID2D1RenderTarget, New D2D1_COLOR_F(Convert.ToSingle(oControl.BackColor.A / 255),
      368. Convert.ToSingle(oControl.BackColor.R / 255),
      369. Convert.ToSingle(oControl.BackColor.G / 255),
      370. Convert.ToSingle(oControl.BackColor.B / 255)))
      371. ' zeichnet das ID2D1SvgDocument in den ID2D1DeviceContext5 (ID2D1HwndRenderTarget)
      372. D2D1DeviceContext5_DrawSvgDocument(pID2D1DeviceContext5, pID2D1SvgDocument)
      373. ' zeichnen in das ID2D1HwndRenderTarget beenden
      374. bolRet = D2D1RenderTarget_EndDraw(pID2D1RenderTarget)
      375. End If
      376. Release(pID2D1SvgDocument)
      377. End If
      378. Release(pIStream)
      379. End If
      380. Release(pID2D1DeviceContext5)
      381. End If
      382. Release(pID2D1RenderTarget)
      383. End If
      384. Release(pID2D1Factory)
      385. End If
      386. End If
      387. Return bolRet
      388. End Function
      389. #End Region
      390. #Region "Private Functions"
      391. '----==== ID2D1Factory Functions ====----
      392. Private Function D2D1Factory_CreateHwndRenderTarget(pID2D1Factory As IntPtr,
      393. renderTargetProperties As D2D1_RENDER_TARGET_PROPERTIES,
      394. hwndRenderTargetProperties As D2D1_HWND_RENDER_TARGET_PROPERTIES,
      395. ByRef pID2D1HwndRenderTarget As IntPtr) As Boolean
      396. Dim bolRet As Boolean = False
      397. Dim pVTablePtr As IntPtr = IntPtr.Zero
      398. If pID2D1Factory <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1Factory, VTable_Interfaces.CreateHwndRenderTarget, pVTablePtr) Then
      399. Dim Method As ID2D1Factory_CreateHwndRenderTarget = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      400. GetType(ID2D1Factory_CreateHwndRenderTarget)),
      401. ID2D1Factory_CreateHwndRenderTarget)
      402. If Method.Invoke(pID2D1Factory, renderTargetProperties, hwndRenderTargetProperties, pID2D1HwndRenderTarget) = S_OK Then
      403. bolRet = True
      404. End If
      405. End If
      406. Return bolRet
      407. End Function
      408. '----==== ID2D1RenderTarget Functions ====----
      409. Private Sub D2D1RenderTarget_Clear(pID2D1RenderTarget As IntPtr,
      410. Optional color As D2D1_COLOR_F? = Nothing)
      411. Dim tColor As D2D1_COLOR_F = If(color.HasValue, CType(color, D2D1_COLOR_F), New D2D1_COLOR_F(1, 0, 0, 0))
      412. Dim pVTablePtr As IntPtr = IntPtr.Zero
      413. If pID2D1RenderTarget <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1RenderTarget, VTable_Interfaces.Clear, pVTablePtr) Then
      414. Dim Method As ID2D1RenderTarget_Clear = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      415. GetType(ID2D1RenderTarget_Clear)),
      416. ID2D1RenderTarget_Clear)
      417. Method.Invoke(pID2D1RenderTarget, tColor)
      418. End If
      419. End Sub
      420. Private Sub D2D1RenderTarget_BeginDraw(pID2D1RenderTarget As IntPtr)
      421. Dim pVTablePtr As IntPtr = IntPtr.Zero
      422. If pID2D1RenderTarget <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1RenderTarget, VTable_Interfaces.BeginDraw, pVTablePtr) Then
      423. Dim Method As ID2D1RenderTarget_BeginDraw = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      424. GetType(ID2D1RenderTarget_BeginDraw)),
      425. ID2D1RenderTarget_BeginDraw)
      426. Method.Invoke(pID2D1RenderTarget)
      427. End If
      428. End Sub
      429. Private Function D2D1RenderTarget_EndDraw(pID2D1RenderTarget As IntPtr,
      430. Optional ByRef tag1 As D2D1_TAG = Nothing,
      431. Optional ByRef tag2 As D2D1_TAG = Nothing) As Boolean
      432. Dim bolRet As Boolean = False
      433. Dim pVTablePtr As IntPtr = IntPtr.Zero
      434. If pID2D1RenderTarget <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1RenderTarget, VTable_Interfaces.EndDraw, pVTablePtr) Then
      435. Dim Method As ID2D1RenderTarget_EndDraw = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      436. GetType(ID2D1RenderTarget_EndDraw)),
      437. ID2D1RenderTarget_EndDraw)
      438. If Method.Invoke(pID2D1RenderTarget, tag1, tag2) = S_OK Then bolRet = True
      439. End If
      440. Return bolRet
      441. End Function
      442. '----==== ID2D1HwndRenderTarget Functions ====----
      443. Public Function D2D1HwndRenderTarget_Resize(pID2D1HwndRenderTarget As IntPtr,
      444. pixelSize As D2D1_SIZE_U) As Boolean
      445. Dim bolRet As Boolean = False
      446. Dim pVTablePtr As IntPtr = IntPtr.Zero
      447. If pID2D1HwndRenderTarget <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1HwndRenderTarget, VTable_Interfaces.Resize, pVTablePtr) Then
      448. Dim Method As ID2D1HwndRenderTarget_Resize = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      449. GetType(ID2D1HwndRenderTarget_Resize)),
      450. ID2D1HwndRenderTarget_Resize)
      451. If Method.Invoke(pID2D1HwndRenderTarget, pixelSize) = S_OK Then bolRet = True
      452. End If
      453. Return bolRet
      454. End Function
      455. '----==== ID2D1DeviceContext5 Functions ====----
      456. Private Function D2D1DeviceContext5_CreateSvgDocument(pID2D1DeviceContext5 As IntPtr,
      457. inputXmlStream As IntPtr,
      458. viewportSize As D2D1_SIZE_F,
      459. ByRef pID2D1SvgDocument As IntPtr) As Boolean
      460. Dim bolRet As Boolean = False
      461. Dim pVTablePtr As IntPtr = IntPtr.Zero
      462. If pID2D1DeviceContext5 <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1DeviceContext5, VTable_Interfaces.CreateSvgDocument, pVTablePtr) Then
      463. Dim Method As ID2D1DeviceContext5_CreateSvgDocument = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      464. GetType(ID2D1DeviceContext5_CreateSvgDocument)),
      465. ID2D1DeviceContext5_CreateSvgDocument)
      466. If Method.Invoke(pID2D1DeviceContext5, inputXmlStream, viewportSize, pID2D1SvgDocument) = S_OK Then bolRet = True
      467. End If
      468. Return bolRet
      469. End Function
      470. Private Sub D2D1DeviceContext5_DrawSvgDocument(pID2D1DeviceContext5 As IntPtr,
      471. pID2D1SvgDocument As IntPtr)
      472. Dim pVTablePtr As IntPtr = IntPtr.Zero
      473. If pID2D1DeviceContext5 <> IntPtr.Zero AndAlso GetVTablePtr(pID2D1DeviceContext5, VTable_Interfaces.DrawSvgDocument, pVTablePtr) Then
      474. Dim Method As ID2D1DeviceContext5_DrawSvgDocument = DirectCast(Marshal.GetDelegateForFunctionPointer(pVTablePtr,
      475. GetType(ID2D1DeviceContext5_DrawSvgDocument)),
      476. ID2D1DeviceContext5_DrawSvgDocument)
      477. Method.Invoke(pID2D1DeviceContext5, pID2D1SvgDocument)
      478. End If
      479. End Sub
      480. '----==== Release Interface ====----
      481. Public Sub Release(ByRef pInterface As IntPtr)
      482. If pInterface <> IntPtr.Zero Then
      483. If Marshal.Release(pInterface) = 0 Then
      484. pInterface = IntPtr.Zero
      485. End If
      486. End If
      487. End Sub
      488. '----==== Fetches the function pointer of the function from the vtable ====----
      489. Private Function GetVTablePtr(pInterface As IntPtr,
      490. intMethodNumber As Integer,
      491. ByRef pVTablePtr As IntPtr) As Boolean
      492. Dim bolRet As Boolean = False
      493. If pInterface <> IntPtr.Zero AndAlso intMethodNumber >= 0 Then
      494. Dim pVTablePtrs As IntPtr() = New IntPtr(0) {}
      495. Marshal.Copy(IntPtr.Add(Marshal.ReadIntPtr(pInterface),
      496. IntPtr.Size * intMethodNumber), pVTablePtrs, 0, 1)
      497. pVTablePtr = pVTablePtrs(0)
      498. bolRet = True
      499. End If
      500. Return bolRet
      501. End Function
      502. #End Region
      503. End Module



      @RodFromGermany Ich hänge hier mal zwei SVGs in einer ZIP mit dran.

      Hi
      Was ich vergessen hatte zu schreiben war, das das laden und rendern einer SVG per Direct2D erst ab dem Windows 10 Creators Update funktioniert und das gab es glaub 2017.
      Dateien
      • SVGs.zip

        (128,3 kB, 64 mal heruntergeladen, zuletzt: )
      Mfg -Franky-

      AKP schrieb:

      Naja. Ich kenne mich mit SVG nicht so richtig aus. Aber bei diesem wird eben nur ein Teil angezeigt. Kann es da eine Mindestgrösse geben? An deinem Code liegt es jedenfalls nicht.


      Vielleicht hat das Webbrowser Control nicht die richtige Grösse und ist einfach zu klein.
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
      @dive26 OK, angekommen, ich hatte die ZIP übersehen.
      Beim Einladen in meine Bildverarbeitung sagt er mir:
      "Es wurde keine passende Imagingkomponente zum Abschließen dieses Vorgangs gefunden."

      Ich werde da mal gezielt "forschen".
      Ist das SVG für Dich "göttlich gegeben" oder genügt irgend ein Vektor-Format?
      In einem älteren Projekt hatte ich WMF- und später EMF-Vektor-Bilder.

      @dive26 @-Franky- Danke für die Bilder, sie sind in in ihrer inneren Struktur alle etwas verschieden, das ist in diesem Sinne gut so.
      Wenn ich sie im Norepad++ öffne, sehe ich XML-Dateien:

      Mit einem XDocument geöffnet und dann durchiteriert sollte es möglich sein, einen einfachen SVG-Viewer zu schreiben.
      Ich probiere mich mal daran.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hi

      Eine SVG ist ja ein ganz normales XML Dokument das über entsprechende Schnittstellen geparst und bearbeitet werden kann. Die Angaben im Root der SVG (x, y, width, height, viewBox <- falls vorhanden), kann man daher entsprechend per Code bearbeiten/hinzufügen/löschen. Per Direct2D wäre es über ID2D1SvgDocument::GetRoot-> ID2D1SvgElement und darüber lassen sich entsprechende Eigenschaften lesen und schreiben und das ganze per ID2D1SvgDocument::SetRoot zurück in die SVG schreiben bevor diese gerendert wird.
      Mfg -Franky-
      @-Franky-

      Vielen Dank für Deinen Code.
      Das Zeichnen auf das Control klappt damit einwandfrei.
      Nun möchte ich aber den dort gezeichneten Inhalt als Bitmap übergeben und/oder als Datei speichern.
      Das klappt auch, aber nur, wenn das Control auch vollständig sichtbar ist.
      Befindet sich das Control außerhalb des sichtbaren Bereiches, dann gehts nicht.
      Gerade bei größeren SVG-Dateien (meine sind z.B. immer 1404*1872 Pixel) geht sich das sogar am Bildschirm nicht aus, auch wenn man möchte.

      Hier meine beiden Versuche, beide ergeben das selbe Problem (bei verdecktem Kontrol).
      Zur Info: ich habe die Funktion so umgeschrieben, dass Sie eine BMP Return bmals Ergebnis übergibt und gleichzeitig das Bild in strDestImgPaht speichert

      VB.NET-Quellcode

      1. 'Ergibt leider nur den sichtbaren Teil eines Controls
      2. '##################################################
      3. Dim myBmp As New Bitmap(ocontrol.Width, ocontrol.Height)
      4. Dim g As Graphics = Graphics.FromImage(myBmp)
      5. Dim pOffset As New Point(ocontrol.Parent.Width - ocontrol.Parent.ClientRectangle.Width - 4, ocontrol.Parent.Height - ocontrol.Parent.ClientRectangle.Height - 4)
      6. pOffset.X += ocontrol.Location.X + ocontrol.Parent.Location.X
      7. pOffset.Y += ocontrol.Location.Y + ocontrol.Parent.Location.Y
      8. g.CopyFromScreen(pOffset, Point.Empty, myBmp.Size)
      9. Return myBmp
      10. g.Dispose()
      11. 'Ergibt leider auch nur den sichtbaren Teil eines Controls
      12. '############################################################
      13. Using bm As New Bitmap(ocontrol.Width, ocontrol.Height, Imaging.PixelFormat.Format24bppRgb)
      14. ocontrol.DrawToBitmap(bm, New Rectangle(0, 0, bm.Width, bm.Height))
      15. bm.Save(strDestImgPaht)
      16. Return bm
      17. End Using
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
      Hi @dive26

      Um das zu machen, was Du möchtest, bedarf es noch ein wenig mehr. Dazu müsstest Du zusätzlich die Windows Imaging Component (WIC) APIs/Interfaces einsetzten. Du müsstest zusätzlich zu Direct2D, WIC initialisieren (ein IWICImagingFactory erstellen), dann per IWICImagingFactory::CreateBitmap ein IWICBitmap in entsprechender Größe Deiner SVG und Farbtiefe (32Bit/ARGB/BGRA/PARGB) erstellen. Per ID2D1Factory::CreateWicBitmapRenderTarget erstellst Du vom IWICBitmap ein ID2D1RenderTarget und von diesem ein ID2D1DeviceContext5 und zeichnest das ID2D1SvgDocument in den ID2D1DeviceContext5. Nach dem zeichnen (ID2D1RenderTarget::EndDraw) kannst Du entweder über IWICBitmap::Lock -> IWICBitmapLock -> IWICBitmapLock::GetDataPointer verwenden (Pointer auf die Pixeldaten), oder IWICBitmapSource (IWICBitmap)::CopyPixels um die Pixeldaten in ein ByteArray zu kopieren. Aus dem ByteArray/Pointer auf das ByteArray/Pixeldaten kann man dann ein GDI+ (.NET)-Bitmap erstellen.

      Wenn es Dir erst einmal nur darum geht, ein SVG zB. als PNG/JPG oder oder zu speichern, dann brauchst Du noch nicht einmal ein Control (PictureBox zB.) dafür weil Breite und Höhe legst Du ja für das IWICBitmap fest. Man kann das IWICBitmap (das ja dann die reingezeichnete SVG enthält) direkt per WIC speichern. Also da kommt nochmal etwas Code dazu. Das schöne an WIC ist das es neben den WIC-Interfaces auch meist entsprechende APIs für diverse WIC-Interfaces und deren Funktionen gibt.

      Dann besteht ja noch das Problem die Bildgröße der SVG auszulesen/festzulegen bzw. diese entsprechend zu skalieren. Wie bereits angedeutet kommst Du per ID2D1SvgDocument::GetRoot an den Root der SVG -> ID2D1SvgElement. Der Root (beginnt ja in der SVG-Datei mit <svg) enthält, falls vorhanden, die entsprechenden Attribute x, y, width, height und/oder viewBox die man über ID2D1SvgElement auslesen/ändern/löschen/anlegen kann. Wenn ich mich recht erinnere, ist schon ein paar Jahre her das ich mich mit SVGs beschäftigt habe, reicht das Attribut viewBox um die Größe der SVG festzulegen, in der die SVG gerendert werden soll. Kannst ja leicht selbst testen. Lösche, falls vorhanden die Attribute x, y, width und height aus dem Root einer SVG-Datei (es wird dann für x=0, y=0, width=100%, height=100% angenommen). Lege das Attribut viewBox="0 0 800 800" (Achtung! Attribute sind Case Sensitive) im Root an. Dann sollte die SVG 800x800 Pixel groß gerendert werden. Nach dem löschen/anlegen/ändern entsprechender Attribute, speichert man das veränderte ID2D1SvgElement per ID2D1SvgDocument::SetRoot wieder zurück. Danach kann das SVG in ein RenderTarget gezeichnet werden. Vllt hilft Dir ja auch das hier weiter in Bezug auf Größe und Skalieren: mediaevent.de/tutorial/svg-viewbox-koordinaten.html
      Mfg -Franky-
      Oh, bin technisch schon im dritten Satz ausgestiegen .

      SVG manuell erstellen hab ich kein Problem. Die SVG Datei oben hab ich manuell ja bereits aus Stifteingabedaten und einer Hintergrundvorlage bereits erstellt.

      Da bleib ich dann beim Webbrowser Control.
      Die 1000 Zeilen mehr an Code schiessen dann übers Ziel hinaus . Zumindest für meine Anwendung.
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

      dive26 schrieb:

      Oh, bin technisch schon im dritten Satz ausgestiegen .

      Ok das Thema SVG ist auch nicht ganz einfach und wenn man mit Direct2D und WIC noch nie was gemacht hat, dann hört sich meine Beschreibung doch sehr abstrakt und kompliziert an.

      dive26 schrieb:

      Die 1000 Zeilen mehr an Code schiessen dann übers Ziel hinaus

      Es dürften, mal grob überschlagen, bedeutend weniger als 1000 Zeilen Code sein die da noch hinzukommen würden.
      Mfg -Franky-
      Wenn es hier spezieller wird würde ich empfehlen einen Thread mit Verweis auf diesen Thread aufzumachen @dive26.
      Dann müsst ihr nicht immer auf die "Freischaltung" warten.


      Grüße

      Ist nun hier:
      Diskussionsthread zu SVG to IMG (Tipps & Tricks)
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()