using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace SmartCoalApplication.SystemLayer
{
public static class PdnGraphics
{
public static PropertyItem CreatePropertyItem()
{
PropertyItem2 pi2 = new PropertyItem2(0, 0, 0, new byte[0]);
return pi2.ToPropertyItem();
}
public static PropertyItem ClonePropertyItem(PropertyItem pi)
{
byte[] valueClone;
if (pi.Value == null)
{
valueClone = new byte[0];
}
else
{
valueClone = (byte[])pi.Value.Clone();
}
PropertyItem2 pi2 = new PropertyItem2(pi.Id, pi.Len, pi.Type, valueClone);
return pi2.ToPropertyItem();
}
public static string SerializePropertyItem(PropertyItem pi)
{
PropertyItem2 pi2 = PropertyItem2.FromPropertyItem(pi);
return pi2.ToBlob();
}
public static PropertyItem DeserializePropertyItem(string piBlob)
{
PropertyItem2 pi2 = PropertyItem2.FromBlob(piBlob);
return pi2.ToPropertyItem();
}
internal unsafe static void GetRegionScans(IntPtr hRgn, out Rectangle[] scans, out int area)
{
uint bytes = 0;
int countdown = 100;
int error = 0;
while (countdown > 0)
{
bytes = SafeNativeMethods.GetRegionData(hRgn, 0, (NativeStructs.RGNDATA*)IntPtr.Zero);
error = Marshal.GetLastWin32Error();
if (bytes == 0)
{
--countdown;
System.Threading.Thread.Sleep(5);
}
else
{
break;
}
}
// But if we retry several times and it still messes up then we will finally give up.
if (bytes == 0)
{
throw new Win32Exception(error, "GetRegionData returned " + bytes.ToString() + ", GetLastError() = " + error.ToString());
}
byte* data;
// Up to 512 bytes, allocate on the stack. Otherwise allocate from the heap.
if (bytes <= 512)
{
byte* data1 = stackalloc byte[(int)bytes];
data = data1;
}
else
{
data = (byte*)Memory.Allocate(bytes).ToPointer();
}
try
{
NativeStructs.RGNDATA* pRgnData = (NativeStructs.RGNDATA*)data;
uint result = SafeNativeMethods.GetRegionData(hRgn, bytes, pRgnData);
if (result != bytes)
{
throw new OutOfMemoryException("SafeNativeMethods.GetRegionData returned 0");
}
NativeStructs.RECT* pRects = NativeStructs.RGNDATA.GetRectsPointer(pRgnData);
scans = new Rectangle[pRgnData->rdh.nCount];
area = 0;
for (int i = 0; i < scans.Length; ++i)
{
scans[i] = Rectangle.FromLTRB(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom);
area += scans[i].Width * scans[i].Height;
}
pRects = null;
pRgnData = null;
}
finally
{
if (bytes > 512)
{
Memory.Free(new IntPtr(data));
}
}
}
///
/// Retrieves an array of rectangles that approximates a region, and computes the
/// pixel area of it. This method is necessary to work around some bugs in .NET
/// and to increase performance for the way in which we typically use this data.
///
/// The Region to retrieve data from.
/// An array of Rectangle to put the scans into.
/// An integer to write the computed area of the region into.
///
/// Note to implementors: Simple implementations may simple call region.GetRegionScans()
/// and process the data for the 'out' variables.
public static void GetRegionScans(Region region, out Rectangle[] scans, out int area)
{
using (NullGraphics nullGraphics = new NullGraphics())
{
IntPtr hRgn = IntPtr.Zero;
try
{
hRgn = region.GetHrgn(nullGraphics.Graphics);
GetRegionScans(hRgn, out scans, out area);
}
finally
{
if (hRgn != IntPtr.Zero)
{
SafeNativeMethods.DeleteObject(hRgn);
hRgn = IntPtr.Zero;
}
}
}
GC.KeepAlive(region);
}
}
}