Re: Problems using ordinary GDI operations on 32bit Bitmap
- From: "Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx>
- Date: Mon, 1 Aug 2005 11:53:39 -0400
Below is a test case that demonstrates how to use the GDI functions
with bitmaps with an alpha channel:
Save as Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace hbitmap
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
public const int transparent = 1;
public const int opaque = 2;
public const int AC_SRC_ALPHA = 1;
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItemDraw;
private System.Windows.Forms.MenuItem menuItemOpaque;
private System.Windows.Forms.MenuItem menuItemBitmap3;
private System.Windows.Forms.MenuItem menuItemFormat32bppARGB;
private System.Windows.Forms.MenuItem menuItemFormat32bppPARGB;
public const int AC_SRC_OVER = 0;
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
};
public enum TernaryRasterOperations
{
SRCCOPY = 0x00CC0020, // dest = source
SRCPAINT = 0x00EE0086, // dest = source OR dest
SRCAND = 0x008800C6, // dest = source AND dest
SRCINVERT = 0x00660046, // dest = source XOR dest
SRCERASE = 0x00440328, // dest = source AND (NOT dest)
NOTSRCCOPY = 0x00330008, // dest = (NOT source)
NOTSRCERASE = 0x001100A6, // dest = (NOT src) AND (NOT dest)
MERGECOPY = 0x00C000CA, // dest = (source AND pattern)
MERGEPAINT = 0x00BB0226, // dest = (NOT source) OR dest
PATCOPY = 0x00F00021, // dest = pattern
PATPAINT = 0x00FB0A09, // dest = DPSnoo
PATINVERT = 0x005A0049, // dest = pattern XOR dest
DSTINVERT = 0x00550009, // dest = (NOT dest)
BLACKNESS = 0x00000042, // dest = BLACK
WHITENESS = 0x00FF0062, // dest = WHITE
};
[DllImport("Msimg32.dll")]
public static extern bool AlphaBlend(
IntPtr hdcDest, // handle to destination DC
int nXOriginDest, // x-coord of upper-left corner
int nYOriginDest, // y-coord of upper-left corner
int nWidthDest, // destination width
int nHeightDest, // destination height
IntPtr hdcSrc, // handle to source DC
int nXOriginSrc, // x-coord of upper-left corner
int nYOriginSrc, // y-coord of upper-left corner
int nWidthSrc, // source width
int nHeightSrc, // source height
BLENDFUNCTION blendFunction // alpha-blending function
);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hBitmap);
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc,
TernaryRasterOperations dwRop );
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC( IntPtr hdc );
[DllImport("gdi32.dll")]
public static extern bool DeleteDC( IntPtr hdc );
[DllImport("gdi32.dll")]
public static extern int SetBkMode( IntPtr hdc, int iBkMode );
[DllImport("gdi32.dll")]
public static extern int SetBkColor( IntPtr hdc, int crColor );
[DllImport("gdi32.dll")]
public static extern int SetTextColor( IntPtr hdc, int crColor );
[DllImport("user32.dll")]
public static extern IntPtr GetDC( IntPtr hWnd );
[DllImport("user32.dll")]
public static extern bool ReleaseDC( IntPtr hWnd, IntPtr hdc );
Bitmap bm;
IntPtr hBitmap;
IntPtr hMemDC;
IntPtr hOldBitmap;
bool bOpaque;
/// <summary>
///
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItemDraw = new System.Windows.Forms.MenuItem();
this.menuItemOpaque = new System.Windows.Forms.MenuItem();
this.menuItemBitmap3 = new System.Windows.Forms.MenuItem();
this.menuItemFormat32bppARGB = new System.Windows.Forms.MenuItem();
this.menuItemFormat32bppPARGB = new System.Windows.Forms.MenuItem();
//
// mainMenu1
//
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItemBitmap3,
this.menuItemDraw});
//
// menuItemDraw
//
this.menuItemDraw.Index = 1;
this.menuItemDraw.MenuItems.AddRange(new System.Windows.Forms.MenuItem[]
{
this.menuItemOpaque});
this.menuItemDraw.Text = "Draw";
//
// menuItemOpaque
//
this.menuItemOpaque.Checked = true;
this.menuItemOpaque.Index = 0;
this.menuItemOpaque.Text = "Opaque";
this.menuItemOpaque.Click += new
System.EventHandler(this.menuItemOpaque_Click);
//
// menuItemBitmap3
//
this.menuItemBitmap3.Index = 0;
this.menuItemBitmap3.MenuItems.AddRange(new
System.Windows.Forms.MenuItem[] {
this.menuItemFormat32bppARGB,
this.menuItemFormat32bppPARGB});
this.menuItemBitmap3.Text = "Bitmap";
//
// menuItemFormat32bppARGB
//
this.menuItemFormat32bppARGB.Checked = true;
this.menuItemFormat32bppARGB.Index = 0;
this.menuItemFormat32bppARGB.Text = "Format32bppARGB";
this.menuItemFormat32bppARGB.Click += new
System.EventHandler(this.menuItemFormat32bppARGB_Click);
//
// menuItemFormat32bppPARGB
//
this.menuItemFormat32bppPARGB.Index = 1;
this.menuItemFormat32bppPARGB.Text = "Format32bppPARGB";
this.menuItemFormat32bppPARGB.Click += new
System.EventHandler(this.menuItemFormat32bppPARGB_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Menu = this.mainMenu1;
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.Paint += new
System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
this.Leave += new System.EventHandler(this.Form1_Leave);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
// Do something with hBitmap.
IntPtr hdc = e.Graphics.GetHdc();
if ( this.bOpaque )
BitBlt(hdc, 0, 0, bm.Width, bm.Height, hMemDC, 0, 0,
TernaryRasterOperations.SRCCOPY);
else
{
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xFF;
bf.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(hdc, 0, 0, bm.Width, bm.Height, hMemDC, 0, 0, bm.Width,
bm.Height, bf );
}
e.Graphics.ReleaseHdc(hdc);
}
private void Form1_Load(object sender, System.EventArgs e)
{
this.bOpaque = true;
this.BackColor = Color.White;
this.bm = new Bitmap("c:\\temp\\PP0N6A08.png");
SelectObject(this.hMemDC, this.hOldBitmap );
DeleteObject(this.hBitmap);
DeleteDC(this.hMemDC);
this.hBitmap = bm.GetHbitmap(this.bm.GetPixel(0,0));
IntPtr hDC = GetDC( (IntPtr)null );
this.hMemDC = CreateCompatibleDC(hDC);
ReleaseDC( (IntPtr)null, hDC );
this.hOldBitmap = SelectObject(hMemDC, hBitmap );
}
private void Form1_Leave(object sender, System.EventArgs e)
{
this.bm.Dispose();
SelectObject(this.hMemDC, this.hOldBitmap );
DeleteDC(this.hMemDC);
DeleteObject(this.hBitmap);
}
private void menuItemOpaque_Click(object sender, System.EventArgs e)
{
bOpaque = !bOpaque;
if ( bOpaque )
{
menuItemOpaque.Checked = true;
Form1.ActiveForm.Invalidate();
}
else
{
menuItemOpaque.Checked = false;
Form1.ActiveForm.Invalidate();
}
}
private void menuItemFormat32bppARGB_Click(object sender, System.EventArgs
e)
{
menuItemFormat32bppPARGB.Checked = !menuItemFormat32bppPARGB.Checked;
menuItemFormat32bppARGB.Checked = true;
bm.Dispose();
this.bm = new Bitmap("c:\\temp\\PP0N6A08.png");
SelectObject(this.hMemDC, this.hOldBitmap );
DeleteObject(this.hBitmap);
DeleteDC(this.hMemDC);
this.hBitmap = bm.GetHbitmap(this.bm.GetPixel(0,0));
IntPtr hDC = GetDC( (IntPtr)null );
this.hMemDC = CreateCompatibleDC(hDC);
ReleaseDC( (IntPtr)null, hDC );
this.hOldBitmap = SelectObject(hMemDC, hBitmap );
Form1.ActiveForm.Invalidate();
}
private void menuItemFormat32bppPARGB_Click(object sender,
System.EventArgs e)
{
menuItemFormat32bppARGB.Checked = !menuItemFormat32bppARGB.Checked;
menuItemFormat32bppPARGB.Checked = true;
bm.Dispose();
Bitmap temp = new Bitmap("c:\\temp\\PP0N6A08.png");
this.bm = new Bitmap( temp.Width, temp.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb );
Graphics g = Graphics.FromImage( bm );
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
Rectangle rect = new Rectangle(0,0,temp.Width, temp.Height);
g.DrawImage( temp, rect );
g.Dispose();
temp.Dispose();
SelectObject(this.hMemDC, this.hOldBitmap );
DeleteObject(this.hBitmap);
DeleteDC(this.hMemDC);
this.hBitmap = bm.GetHbitmap(this.bm.GetPixel(0,0));
IntPtr hDC = GetDC( (IntPtr)null );
this.hMemDC = CreateCompatibleDC(hDC);
ReleaseDC( (IntPtr)null, hDC );
this.hOldBitmap = SelectObject(hMemDC, hBitmap );
Form1.ActiveForm.Invalidate();
}
}
}
I got the .png image from the PNG test image suite here:
http://www.schaik.com/pngsuite/pngsuite.html
"Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx> wrote in message
news:elUEScdlFHA.3336@xxxxxxxxxxxxxxxxxxxxxxx
> You must premultiply the alpha channel against the color channels.
>
> See the documentation for the AlphaBlend function for details.
>
>
> "yuval" <yuval.gross@xxxxxxxxx> wrote in message
> news:1122798969.086056.56970@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
>> Hi,
>> I'm having a predefined 32bit Bitmap that has an alpha channel.
>>
>> I simply want to perform additional operations at runtime such as
>> drawing text or general drawing on this bitmap.
>>
>> I discovered that the ordinary GDI functions (FillRect, TextOut, etc.)
>> simply destroy the alpha bytes while drawing (actually setting these
>> bytes to zero). This of course corrupts the bitmap alpha channel. I
>> couldn't find any mode or flag that tells the HDC that the bitmap is
>> 32bit and ignore the alpha channel...
>>
>> Is there a way to use GDI functions on 32 bitmap without touching the
>> alpha channel?
>>
>> Although I have found a solution to this problem by using GDI+
>> functions which do not automatically override the alpha channel, I
>> still wanna use the ordinary GDI operations without involving GDI+.
>>
>
>
.
- References:
- Problems using ordinary GDI operations on 32bit Bitmap
- From: yuval
- Re: Problems using ordinary GDI operations on 32bit Bitmap
- From: Michael Phillips, Jr.
- Problems using ordinary GDI operations on 32bit Bitmap
- Prev by Date: RE: Getting DC of printer
- Next by Date: RE: GDI+ DrawString(...) Limitation???
- Previous by thread: Re: Problems using ordinary GDI operations on 32bit Bitmap
- Next by thread: Re: Problems using ordinary GDI operations on 32bit Bitmap
- Index(es):
Relevant Pages
|