How to draw a contour of a collection of rectangles?

As part of the project I'm working on, I have to keep and restore areas of the magic wand from the image. To retrieve data for storage, I use the GetRegionData method . As stated in the specification, this method:

Returns a RegionData that represents information describing this region.

I store byte[], stored in a property RegionData.Datain a base64 string, so I can get it RegionDatalater through a somewhat unconventional method:

// This "instantiates" a RegionData object by simply initiating an object and setting the object type pointer to the specified type.
// Constructors don't run, but in this very specific case - they don't have to. The RegionData only member is a "data" byte array, which we set right after.
var regionData =
    (RegionData)FormatterServices.GetUninitializedObject(typeof(RegionData));
regionData.Data = bytes;

Then I create Regionand pass the above object RegionDatain the constructor and call GetRegionScansto get the rectangle objects that make up the area:

var region = new Region(regionData);
RectangleF[] rectangles = region.GetRegionScans(new Matrix());

, , . WinForms, :

using (var g = Graphics.FromImage(picBox.Image))
{
    var p = new Pen(Color.Black, 1f);
    var alternatePen = new Pen(Color.BlueViolet, 1f);
    var b = new SolidBrush(picBox.BackColor);
    var niceBrush = new SolidBrush(Color.Orange);

    foreach (var r in rectangles)
    {
        g.DrawRectangle(p,
            new Rectangle(new Point((int)r.Location.X, (int)r.Location.Y),
                new Size((int)r.Width, (int)r.Height)));
    }
}

, :

Rectectles rendered

- , . , , , . - , .

, , , . :

var pointPair = new[]
{
    new Point((int) r.Left, (int) r.Y),
    new Point((int) r.Right, (int) r.Y)
};

g.DrawRectangle(p, pointPair[0].X, pointPair[0].Y, 1, 1);
g.DrawRectangle(p, pointPair[1].X, pointPair[1].Y, 1, 1);

:

Points rendered

, .

, . -, , , .

, Left, Right , .

, .

!

Peter Duniho . SafeHandle , , .

, .

    private void DrawRegionOutline(Graphics graphics, Color color, Region region)
    {
        var regionHandle = new SafeRegionHandle(region, region.GetHrgn(graphics));
        var deviceContext = new SafeDeviceContextHandle(graphics);
        var brushHandle = new SafeBrushHandle(color);

        using (regionHandle)
        using (deviceContext)
        using (brushHandle)
            FrameRgn(deviceContext.DangerousGetHandle(), regionHandle.DangerousGetHandle(), brushHandle.DangerousGetHandle(), 1, 1);
    }

SafeHandleNative

SafeHandleZeroOrMinusOneIsInvalid, , .

[HostProtection(MayLeakOnAbort = true)]
[SuppressUnmanagedCodeSecurity]
public abstract class SafeNativeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    #region Platform Invoke

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    protected internal static extern bool CloseHandle(IntPtr hObject);

    #endregion

    /// <summary>
    /// Initializes a new instance of the <see cref="SafeNativeHandle"/> class.
    /// </summary>
    protected SafeNativeHandle() : base(true)
    {}

    /// <summary>
    /// Initializes a new instance of the <see cref="SafeNativeHandle"/> class.
    /// </summary>
    /// <param name="handle">The handle.</param>
    protected SafeNativeHandle(IntPtr handle)
        : base(true)
    {
        SetHandle(handle);
    }
}

, Region, Brush . SafeNativeHandle, , , , . , Win32 API, .

public class SafeRegionHandle : SafeNativeHandle
{
    private readonly Region _region;

    /// <summary>
    /// Initializes a new instance of the <see cref="SafeRegionHandle" /> class.
    /// </summary>
    /// <param name="region">The region.</param>
    /// <param name="handle">The handle.</param>
    public SafeRegionHandle(Region region, IntPtr handle)
    {
        _region = region;
        base.handle = handle;
    }

    /// <summary>
    /// When overridden in a derived class, executes the code required to free the handle.
    /// </summary>
    /// <returns>
    /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a releaseHandleFailed MDA Managed Debugging Assistant.
    /// </returns>
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    protected override bool ReleaseHandle()
    {
        try
        {
            _region.ReleaseHrgn(handle);
        }
        catch
        {
            return false;
        }

        return true;
    }
}
+4
1

, . , , , .

, ,.NET API . API Windows. , , :

[DllImport("gdi32")]
static extern bool FrameRgn(System.IntPtr hDC, System.IntPtr hRgn, IntPtr hBrush, int nWidth, int nHeight);

[DllImport("gdi32")]
static extern IntPtr CreateSolidBrush(uint colorref);

[DllImport("gdi32.dll")]
static extern bool DeleteObject([In] IntPtr hObject);

[StructLayout(LayoutKind.Explicit)]
struct COLORREF
{
    [FieldOffset(0)]
    public uint colorref;
    [FieldOffset(0)]
    public byte red;
    [FieldOffset(1)]
    public byte green;
    [FieldOffset(2)]
    public byte blue;

    public COLORREF(Color color)
        : this()
    {
        red = color.R;
        green = color.G;
        blue = color.B;
    }
}

void DrawRegion(Graphics graphics, Color color, Region region)
{
    COLORREF colorref = new COLORREF(color);
    IntPtr hdc = IntPtr.Zero, hbrush = IntPtr.Zero, hrgn = IntPtr.Zero;

    try
    {
        hrgn = region.GetHrgn(graphics);
        hdc = graphics.GetHdc();
        hbrush = CreateSolidBrush(colorref.colorref);

        FrameRgn(hdc, hrgn, hbrush, 1, 1);
    }
    finally
    {
        if (hrgn != IntPtr.Zero)
        {
            region.ReleaseHrgn(hrgn);
        }

        if (hbrush != IntPtr.Zero)
        {
            DeleteObject(hbrush);
        }

        if (hdc != IntPtr.Zero)
        {
            graphics.ReleaseHdc(hdc);
        }
    }
}

DrawRegion() Paint , Graphics, Image, .

, . , , SafeHandle, using try/finally ( , ).

+1

All Articles