region clipping in Win 2k

  • Thread starter Thread starter Robb
  • Start date Start date
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
 
Hi Robb,

Thanks for reporting this issue.

I could repro this problem on a win2000 test machine, I'll do some research
on it and update this thread as soon as I get some result.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
You should not reply this mail directly, "Online" should be removed before
sending.
 
Hi Robb,

I'm not sure if it is a bug, but we can work around this problem by using
the Windows API SetWindowRgn.
Here is the code snippet.
If it doesn't work for you, please reply to this thread to let me know!
Thanks!
<code>
public Form1()
{
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;

Region r = BitmapToRegion.Convert( bm, col,
TransparencyMode.ColorKeyTransparent );
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

Graphics g = this.CreateGraphics();
SetWindowRgn(this.Handle,r.GetHrgn(g),1);
g.Dispose();

this.BackgroundImage = bm;
}
[DllImport("user32.dll")]
public extern static int SetWindowRgn(
IntPtr hWnd, // handle to window
IntPtr hRgn, // handle to region
int bRedraw // window redraw option
);
</code>


Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
You should not reply this mail directly, "Online" should be removed before
sending.
 
I've seen that before and it does seem like a bug. It works when you use the
api because you're forcing the handle to be created (by asking for the
..Handle). Setting the Region property should work as long as you wait until
the Handle of the form has been created.
 
Back
Top