R
Robb
Hi All,
I am using an algorithm to put together a path, create a
region, and then use it to clip my custom form to give it
a "skin." This apparently works great in XP, but my
testing in Win 2k has shown that wehn I assign the region
to the form (which is borderless in its properties) it
seems to skew the location of the region up and to the
left of thje background graphic (which was used to create
the region), by what looks like the size of the titlebar
and a normal border on a window. Thus you end up with a
clipped region of the right shape, but not algned with the
image you used to clip with.
Here is the pertinent code:
the bitmap to region function (note this was not created
by me, but was posted on the web, and it successfully
recreates the problem):
///<author>Arild Fines</author>
///<date>20.04.2002</date>
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace BitmapToRegion
{
/// <summary>
/// determines the meaning of the transparencyKey
/// argument to the Convert method
/// </summary>
public enum TransparencyMode
{
/// <summary>
/// the color key is used to define the transparent
/// region of the bitmap
/// </summary>
ColorKeyTransparent,
/// <summary>
/// the color key is used to define the area that
/// should _not_ be transparent
/// </summary>
ColorKeyOpaque
}
/// <summary>
/// a class to convert a color-keyed bitmap into a region
/// </summary>
public class BitmapToRegion
{
/// <summary>
/// ctor made private to avoid instantiation
/// </summary>
private BitmapToRegion()
{}
/// <summary>
/// the meat of this class
/// converts the bitmap to a region by scanning each
/// line one by one
/// this method will not affect the original bitmap in
/// any way
/// </summary>
/// <param name="bitmap">The bitmap to convert</param>
/// <param name="transparencyKey">The color which will
/// indicate either transparency or opacity</param>
/// <param name="mode">Whether the transparency key
/// should indicate the transparent or the opaque
/// region</param>
public unsafe static Region Convert( Bitmap bitmap,
Color transparencyKey,
TransparencyMode mode )
{
//sanity check
if ( bitmap == null )
throw new ArgumentNullException( "Bitmap",
"Bitmap cannot be null!" );
// flag = true means the color key represents
// the opaque color
bool modeFlag = ( mode ==
transparencyMode.ColorKeyOpaque );
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = bitmap.GetBounds( ref unit );
Rectangle bounds = new Rectangle( (int)boundsF.Left,
(int)boundsF.Top,
(int)boundsF.Width,
(int)boundsF.Height );
uint key = (uint)((transparencyKey.A << 24) |
(transparencyKey.R << 16) |
(transparencyKey.G << 8) |
(transparencyKey.B << 0));
//get access to the raw bits of the image
BitmapData bitmapData = bitmap.LockBits( bounds,
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb );
uint* pixelPtr = (uint*)bitmapData.Scan0.ToPointer();
//avoid property accessors in the for
int yMax = (int)boundsF.Height;
int xMax = (int)boundsF.Width;
//to store all the little rectangles in
GraphicsPath path = new GraphicsPath();
for ( int y = 0; y < yMax; y++ )
{
//store the pointer so we can offset the stride
//directly from it later
//to get to the next line
byte* basePos = (byte*)pixelPtr;
for ( int x = 0; x < xMax; x++, pixelPtr++ )
{
//is this transparent? if yes,
//just go on with the loop
if ( modeFlag ^ ( *pixelPtr == key ) )
continue;
//store where the scan starts
int x0 = x;
//not transparent - scan until we
//find the next transparent byte
while( x < xMax &&
!( modeFlag ^ ( *pixelPtr == key ) ) )
{
++x;
pixelPtr++;
}
//add the rectangle we have found to the path
path.AddRectangle(new Rectangle( x0, y,
x-x0, 1 ) );
}
//jump to the next line
pixelPtr = (uint*)(basePos + bitmapData.Stride);
}
//now create the region from all the rectangles
Region region = new Region( path );
//clean up
path.Dispose();
bitmap.UnlockBits( bitmapData );
return region;
}
}
}
=======================
The invoking code (snipped):
....
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container
components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
Bitmap bm = (Bitmap)Bitmap.FromStream(
this.GetType().Assembly.GetManifestResourceStream(
"BitmapToRegion.Image1.bmp" ) );
Color col = bm.GetPixel( 1, 1 );
this.Width = bm.Width;
this.Height = bm.Height;
this.Region = BitmapToRegion.Convert( bm, col,
TransparencyMode.ColorKeyTransparent );
this.BackgroundImage = bm;
}
....
=========
Like I said, apparently works great in XP, but skews the
clipping region in Win 2k. Any ideas / workarounds?
Thanks,
Robb
I am using an algorithm to put together a path, create a
region, and then use it to clip my custom form to give it
a "skin." This apparently works great in XP, but my
testing in Win 2k has shown that wehn I assign the region
to the form (which is borderless in its properties) it
seems to skew the location of the region up and to the
left of thje background graphic (which was used to create
the region), by what looks like the size of the titlebar
and a normal border on a window. Thus you end up with a
clipped region of the right shape, but not algned with the
image you used to clip with.
Here is the pertinent code:
the bitmap to region function (note this was not created
by me, but was posted on the web, and it successfully
recreates the problem):
///<author>Arild Fines</author>
///<date>20.04.2002</date>
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace BitmapToRegion
{
/// <summary>
/// determines the meaning of the transparencyKey
/// argument to the Convert method
/// </summary>
public enum TransparencyMode
{
/// <summary>
/// the color key is used to define the transparent
/// region of the bitmap
/// </summary>
ColorKeyTransparent,
/// <summary>
/// the color key is used to define the area that
/// should _not_ be transparent
/// </summary>
ColorKeyOpaque
}
/// <summary>
/// a class to convert a color-keyed bitmap into a region
/// </summary>
public class BitmapToRegion
{
/// <summary>
/// ctor made private to avoid instantiation
/// </summary>
private BitmapToRegion()
{}
/// <summary>
/// the meat of this class
/// converts the bitmap to a region by scanning each
/// line one by one
/// this method will not affect the original bitmap in
/// any way
/// </summary>
/// <param name="bitmap">The bitmap to convert</param>
/// <param name="transparencyKey">The color which will
/// indicate either transparency or opacity</param>
/// <param name="mode">Whether the transparency key
/// should indicate the transparent or the opaque
/// region</param>
public unsafe static Region Convert( Bitmap bitmap,
Color transparencyKey,
TransparencyMode mode )
{
//sanity check
if ( bitmap == null )
throw new ArgumentNullException( "Bitmap",
"Bitmap cannot be null!" );
// flag = true means the color key represents
// the opaque color
bool modeFlag = ( mode ==
transparencyMode.ColorKeyOpaque );
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = bitmap.GetBounds( ref unit );
Rectangle bounds = new Rectangle( (int)boundsF.Left,
(int)boundsF.Top,
(int)boundsF.Width,
(int)boundsF.Height );
uint key = (uint)((transparencyKey.A << 24) |
(transparencyKey.R << 16) |
(transparencyKey.G << 8) |
(transparencyKey.B << 0));
//get access to the raw bits of the image
BitmapData bitmapData = bitmap.LockBits( bounds,
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb );
uint* pixelPtr = (uint*)bitmapData.Scan0.ToPointer();
//avoid property accessors in the for
int yMax = (int)boundsF.Height;
int xMax = (int)boundsF.Width;
//to store all the little rectangles in
GraphicsPath path = new GraphicsPath();
for ( int y = 0; y < yMax; y++ )
{
//store the pointer so we can offset the stride
//directly from it later
//to get to the next line
byte* basePos = (byte*)pixelPtr;
for ( int x = 0; x < xMax; x++, pixelPtr++ )
{
//is this transparent? if yes,
//just go on with the loop
if ( modeFlag ^ ( *pixelPtr == key ) )
continue;
//store where the scan starts
int x0 = x;
//not transparent - scan until we
//find the next transparent byte
while( x < xMax &&
!( modeFlag ^ ( *pixelPtr == key ) ) )
{
++x;
pixelPtr++;
}
//add the rectangle we have found to the path
path.AddRectangle(new Rectangle( x0, y,
x-x0, 1 ) );
}
//jump to the next line
pixelPtr = (uint*)(basePos + bitmapData.Stride);
}
//now create the region from all the rectangles
Region region = new Region( path );
//clean up
path.Dispose();
bitmap.UnlockBits( bitmapData );
return region;
}
}
}
=======================
The invoking code (snipped):
....
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container
components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
Bitmap bm = (Bitmap)Bitmap.FromStream(
this.GetType().Assembly.GetManifestResourceStream(
"BitmapToRegion.Image1.bmp" ) );
Color col = bm.GetPixel( 1, 1 );
this.Width = bm.Width;
this.Height = bm.Height;
this.Region = BitmapToRegion.Convert( bm, col,
TransparencyMode.ColorKeyTransparent );
this.BackgroundImage = bm;
}
....
=========
Like I said, apparently works great in XP, but skews the
clipping region in Win 2k. Any ideas / workarounds?
Thanks,
Robb