/// <summary> /// Creates a WindowsGraphics object from a Graphics object. Clipping and coordinate transforms /// are preserved. /// /// Notes: /// - The passed Graphics object cannot be used until the WindowsGraphics is disposed /// since it borrows the hdc from the Graphics object locking it. /// - Changes to the hdc using the WindowsGraphics object are not preserved into the Graphics object; /// the hdc is returned to the Graphics object intact. /// /// Some background about how Graphics uses the internal hdc when created from an existing one /// (mail from GillesK from GDI+ team): /// User has an HDC with a particular state: /// Graphics object gets created based on that HDC. We query the HDC for its state and apply it to the Graphics. /// At this stage, we do a SaveHDC and clear everything out of it. /// User calls GetHdc. We restore the HDC to the state it was in and give it to the user. /// User calls ReleaseHdc, we save the current state of the HDC and clear everything /// (so that the graphics state gets applied next time we use it). /// Next time the user calls GetHdc we give him back the state after the second ReleaseHdc. /// (But the state changes between the GetHdc and ReleaseHdc are not applied to the Graphics). /// Please note that this only applies the HDC created graphics, for Bitmap derived graphics, GetHdc creates a new DIBSection and /// things get a lot more complicated. /// </summary> public static WindowsGraphics FromGraphics(Graphics g) { ApplyGraphicsProperties properties = ApplyGraphicsProperties.All; return(WindowsGraphics.FromGraphics(g, properties)); }
public static WindowsGraphics FromGraphics(Graphics g, ApplyGraphicsProperties properties) { Debug.Assert(g != null, "null Graphics object."); WindowsRegion wr = null; float[] elements = null; Region clipRgn = null; Matrix worldTransf = null; if ((properties & ApplyGraphicsProperties.TranslateTransform) != 0 || (properties & ApplyGraphicsProperties.Clipping) != 0) { object[] data = g.GetContextInfo() as object[]; if (data != null && data.Length == 2) { clipRgn = data[0] as Region; worldTransf = data[1] as Matrix; } if (worldTransf != null) { if ((properties & ApplyGraphicsProperties.TranslateTransform) != 0) { elements = worldTransf.Elements; } worldTransf.Dispose(); } if (clipRgn != null) { if ((properties & ApplyGraphicsProperties.Clipping) != 0) { // We have to create the WindowsRegion and dipose the Region object before locking the Graphics object, // in case of an unlikely exception before releasing the WindowsRegion, the finalizer will do it for us. // (no try-finally block since this method is used frequently - perf). // If the Graphics.Clip has not been set (Region.IsInfinite) we don't need to apply it to the DC. if (!clipRgn.IsInfinite(g)) { wr = WindowsRegion.FromRegion(clipRgn, g); // WindowsRegion will take ownership of the hRegion. } } clipRgn.Dispose(); // Disposing the Region object doesn't destroy the hRegion. } } WindowsGraphics wg = WindowsGraphics.FromHdc(g.GetHdc()); // This locks the Graphics object. wg._graphics = g; // Apply transform and clip if (wr != null) { using (wr) { // If the Graphics object was created from a native DC the actual clipping region is the intersection // beteween the original DC clip region and the GDI+ one - for display Graphics it is the same as // Graphics.VisibleClipBounds. wg.DeviceContext.IntersectClip(wr); } } if (elements != null) { // elements (XFORM) = [eM11, eM12, eM21, eM22, eDx, eDy], eDx/eDy specify the translation offset. wg.DeviceContext.TranslateTransform((int)elements[4], (int)elements[5]); } return(wg); }
public static WindowsGraphics FromGraphics(Graphics g, ApplyGraphicsProperties properties) { Debug.Assert(g != null, "null Graphics object."); WindowsRegion?wr = null; PointF offset = default; if (properties != ApplyGraphicsProperties.None) { Region?clip = null; #if NETCOREAPP3_1_OR_GREATER if (properties.HasFlag(ApplyGraphicsProperties.Clipping)) { g.GetContextInfo(out offset, out clip); } else { g.GetContextInfo(out offset); } #else Matrix?worldTransf = null; if (g.GetContextInfo() is object[] data && data.Length == 2) { if (properties.HasFlag(ApplyGraphicsProperties.Clipping)) { clip = data[0] as Region; } worldTransf = data[1] as Matrix; if (worldTransf != null) { offset = worldTransf.Offset; } } #endif if (clip is not null) { // We have to create the WindowsRegion and dipose the Region object before locking the Graphics object, // in case of an unlikely exception before releasing the WindowsRegion, the finalizer will do it for us. // (no try-finally block since this method is used frequently - perf). // If clipping has not been set (Region.IsInfinite) GetContextInfo will return a null Region. wr = WindowsRegion.FromRegion(clip, g); // WindowsRegion will take ownership of the hRegion. clip.Dispose(); // Disposing the Region object doesn't destroy the hRegion. } } WindowsGraphics wg = FromHdc(g.GetHdc()); // This locks the Graphics object. wg._graphics = g; // Apply transform and clip if (wr is not null) { using (wr) { // If the Graphics object was created from a native DC the actual clipping region is the intersection // beteween the original DC clip region and the GDI+ one - for display Graphics it is the same as // Graphics.VisibleClipBounds. wg.DeviceContext.IntersectClip(wr); } } if (offset != default) { // elements (XFORM) = [eM11, eM12, eM21, eM22, eDx, eDy], eDx/eDy specify the translation offset. wg.DeviceContext.TranslateTransform((int)offset.X, (int)offset.Y); } return(wg); }