1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Runtime.InteropServices; 6 using System.Diagnostics; 7 using System.ComponentModel; 8 using System.Drawing.Drawing2D; 9 using System.Drawing.Imaging; 10 11 namespace System.Drawing 12 { 13 public sealed class TextureBrush : Brush 14 { 15 // When creating a texture brush from a metafile image, the dstRect 16 // is used to specify the size that the metafile image should be 17 // rendered at in the device units of the destination graphics. 18 // It is NOT used to crop the metafile image, so only the width 19 // and height values matter for metafiles. 20 TextureBrush(Image bitmap)21 public TextureBrush(Image bitmap) : this(bitmap, WrapMode.Tile) 22 { 23 } 24 TextureBrush(Image image, WrapMode wrapMode)25 public TextureBrush(Image image, WrapMode wrapMode) 26 { 27 if (image == null) 28 { 29 throw new ArgumentNullException(nameof(image)); 30 } 31 32 if (wrapMode < WrapMode.Tile || wrapMode > WrapMode.Clamp) 33 { 34 throw new InvalidEnumArgumentException(nameof(wrapMode), unchecked((int)wrapMode), typeof(WrapMode)); 35 } 36 37 IntPtr brush = IntPtr.Zero; 38 int status = SafeNativeMethods.Gdip.GdipCreateTexture(new HandleRef(image, image.nativeImage), 39 (int)wrapMode, 40 out brush); 41 SafeNativeMethods.Gdip.CheckStatus(status); 42 43 SetNativeBrushInternal(brush); 44 } 45 TextureBrush(Image image, WrapMode wrapMode, RectangleF dstRect)46 public TextureBrush(Image image, WrapMode wrapMode, RectangleF dstRect) 47 { 48 if (image == null) 49 { 50 throw new ArgumentNullException(nameof(image)); 51 } 52 53 if (wrapMode < WrapMode.Tile || wrapMode > WrapMode.Clamp) 54 { 55 throw new InvalidEnumArgumentException(nameof(wrapMode), unchecked((int)wrapMode), typeof(WrapMode)); 56 } 57 58 IntPtr brush = IntPtr.Zero; 59 int status = SafeNativeMethods.Gdip.GdipCreateTexture2(new HandleRef(image, image.nativeImage), 60 unchecked((int)wrapMode), 61 dstRect.X, 62 dstRect.Y, 63 dstRect.Width, 64 dstRect.Height, 65 out brush); 66 SafeNativeMethods.Gdip.CheckStatus(status); 67 68 SetNativeBrushInternal(brush); 69 } 70 TextureBrush(Image image, WrapMode wrapMode, Rectangle dstRect)71 public TextureBrush(Image image, WrapMode wrapMode, Rectangle dstRect) 72 { 73 if (image == null) 74 { 75 throw new ArgumentNullException(nameof(image)); 76 } 77 78 if (wrapMode < WrapMode.Tile || wrapMode > WrapMode.Clamp) 79 { 80 throw new InvalidEnumArgumentException(nameof(wrapMode), unchecked((int)wrapMode), typeof(WrapMode)); 81 } 82 83 IntPtr brush = IntPtr.Zero; 84 int status = SafeNativeMethods.Gdip.GdipCreateTexture2I(new HandleRef(image, image.nativeImage), 85 unchecked((int)wrapMode), 86 dstRect.X, 87 dstRect.Y, 88 dstRect.Width, 89 dstRect.Height, 90 out brush); 91 SafeNativeMethods.Gdip.CheckStatus(status); 92 93 SetNativeBrushInternal(brush); 94 } 95 TextureBrush(Image image, RectangleF dstRect)96 public TextureBrush(Image image, RectangleF dstRect) : this(image, dstRect, null) { } 97 TextureBrush(Image image, RectangleF dstRect, ImageAttributes imageAttr)98 public TextureBrush(Image image, RectangleF dstRect, ImageAttributes imageAttr) 99 { 100 if (image == null) 101 { 102 throw new ArgumentNullException(nameof(image)); 103 } 104 105 IntPtr brush = IntPtr.Zero; 106 int status = SafeNativeMethods.Gdip.GdipCreateTextureIA(new HandleRef(image, image.nativeImage), 107 new HandleRef(imageAttr, (imageAttr == null) ? 108 IntPtr.Zero : imageAttr.nativeImageAttributes), 109 dstRect.X, 110 dstRect.Y, 111 dstRect.Width, 112 dstRect.Height, 113 out brush); 114 SafeNativeMethods.Gdip.CheckStatus(status); 115 116 SetNativeBrushInternal(brush); 117 } 118 TextureBrush(Image image, Rectangle dstRect)119 public TextureBrush(Image image, Rectangle dstRect) : this(image, dstRect, null) { } 120 TextureBrush(Image image, Rectangle dstRect, ImageAttributes imageAttr)121 public TextureBrush(Image image, Rectangle dstRect, ImageAttributes imageAttr) 122 { 123 if (image == null) 124 { 125 throw new ArgumentNullException(nameof(image)); 126 } 127 128 IntPtr brush = IntPtr.Zero; 129 int status = SafeNativeMethods.Gdip.GdipCreateTextureIAI(new HandleRef(image, image.nativeImage), 130 new HandleRef(imageAttr, (imageAttr == null) ? 131 IntPtr.Zero : imageAttr.nativeImageAttributes), 132 dstRect.X, 133 dstRect.Y, 134 dstRect.Width, 135 dstRect.Height, 136 out brush); 137 SafeNativeMethods.Gdip.CheckStatus(status); 138 139 SetNativeBrushInternal(brush); 140 } 141 TextureBrush(IntPtr nativeBrush)142 internal TextureBrush(IntPtr nativeBrush) 143 { 144 Debug.Assert(nativeBrush != IntPtr.Zero, "Initializing native brush with null."); 145 SetNativeBrushInternal(nativeBrush); 146 } 147 Clone()148 public override object Clone() 149 { 150 IntPtr cloneBrush = IntPtr.Zero; 151 int status = SafeNativeMethods.Gdip.GdipCloneBrush(new HandleRef(this, NativeBrush), out cloneBrush); 152 SafeNativeMethods.Gdip.CheckStatus(status); 153 154 return new TextureBrush(cloneBrush); 155 } 156 157 public Matrix Transform 158 { 159 get 160 { 161 var matrix = new Matrix(); 162 int status = SafeNativeMethods.Gdip.GdipGetTextureTransform(new HandleRef(this, NativeBrush), new HandleRef(matrix, matrix.nativeMatrix)); 163 SafeNativeMethods.Gdip.CheckStatus(status); 164 165 return matrix; 166 } 167 set 168 { 169 if (value == null) 170 { 171 throw new ArgumentNullException(nameof(value)); 172 } 173 174 int status = SafeNativeMethods.Gdip.GdipSetTextureTransform(new HandleRef(this, NativeBrush), new HandleRef(value, value.nativeMatrix)); 175 SafeNativeMethods.Gdip.CheckStatus(status); 176 } 177 } 178 179 public WrapMode WrapMode 180 { 181 get 182 { 183 int mode = 0; 184 int status = SafeNativeMethods.Gdip.GdipGetTextureWrapMode(new HandleRef(this, NativeBrush), out mode); 185 SafeNativeMethods.Gdip.CheckStatus(status); 186 187 return (WrapMode)mode; 188 } 189 set 190 { 191 if (value < WrapMode.Tile || value > WrapMode.Clamp) 192 { 193 throw new InvalidEnumArgumentException(nameof(value), unchecked((int)value), typeof(WrapMode)); 194 } 195 196 int status = SafeNativeMethods.Gdip.GdipSetTextureWrapMode(new HandleRef(this, NativeBrush), unchecked((int)value)); 197 SafeNativeMethods.Gdip.CheckStatus(status); 198 } 199 } 200 201 public Image Image 202 { 203 get 204 { 205 IntPtr image; 206 int status = SafeNativeMethods.Gdip.GdipGetTextureImage(new HandleRef(this, NativeBrush), out image); 207 SafeNativeMethods.Gdip.CheckStatus(status); 208 209 return Image.CreateImageObject(image); 210 } 211 } 212 ResetTransform()213 public void ResetTransform() 214 { 215 int status = SafeNativeMethods.Gdip.GdipResetTextureTransform(new HandleRef(this, NativeBrush)); 216 SafeNativeMethods.Gdip.CheckStatus(status); 217 } 218 219 public void MultiplyTransform(Matrix matrix) => MultiplyTransform(matrix, MatrixOrder.Prepend); 220 MultiplyTransform(Matrix matrix, MatrixOrder order)221 public void MultiplyTransform(Matrix matrix, MatrixOrder order) 222 { 223 if (matrix == null) 224 { 225 throw new ArgumentNullException(nameof(matrix)); 226 } 227 228 // Multiplying the transform by a disposed matrix is a nop in GDI+, but throws 229 // with the libgdiplus backend. Simulate a nop for compatability with GDI+. 230 if (matrix.nativeMatrix == IntPtr.Zero) 231 { 232 return; 233 } 234 235 int status = SafeNativeMethods.Gdip.GdipMultiplyTextureTransform(new HandleRef(this, NativeBrush), 236 new HandleRef(matrix, matrix.nativeMatrix), 237 order); 238 SafeNativeMethods.Gdip.CheckStatus(status); 239 } 240 TranslateTransform(float dx, float dy)241 public void TranslateTransform(float dx, float dy) => TranslateTransform(dx, dy, MatrixOrder.Prepend); 242 TranslateTransform(float dx, float dy, MatrixOrder order)243 public void TranslateTransform(float dx, float dy, MatrixOrder order) 244 { 245 int status = SafeNativeMethods.Gdip.GdipTranslateTextureTransform(new HandleRef(this, NativeBrush), 246 dx, 247 dy, 248 order); 249 SafeNativeMethods.Gdip.CheckStatus(status); 250 } 251 ScaleTransform(float sx, float sy)252 public void ScaleTransform(float sx, float sy) => ScaleTransform(sx, sy, MatrixOrder.Prepend); 253 ScaleTransform(float sx, float sy, MatrixOrder order)254 public void ScaleTransform(float sx, float sy, MatrixOrder order) 255 { 256 int status = SafeNativeMethods.Gdip.GdipScaleTextureTransform(new HandleRef(this, NativeBrush), 257 sx, 258 sy, 259 order); 260 SafeNativeMethods.Gdip.CheckStatus(status); 261 } 262 RotateTransform(float angle)263 public void RotateTransform(float angle) => RotateTransform(angle, MatrixOrder.Prepend); 264 RotateTransform(float angle, MatrixOrder order)265 public void RotateTransform(float angle, MatrixOrder order) 266 { 267 int status = SafeNativeMethods.Gdip.GdipRotateTextureTransform(new HandleRef(this, NativeBrush), 268 angle, 269 order); 270 SafeNativeMethods.Gdip.CheckStatus(status); 271 } 272 } 273 } 274