WinForms FAQ - Bitmaps and Images

Find answers for the most frequently asked questions
Expand All Collapse All

GDI+ has direct support for reading and outputting animated images.

To get at the individual frames, you can use the image’s FrameDimensionList, and then call SelectActiveFrame, by passing in the dimension and the zero based frame index.

First, create a new FrameDimension object:


FrameDimension dimension = new System.Drawing.Imaging.FrameDimension(myImage.FrameDimensionsList[0]);

Once you have the dimension, you can get the frame count:


int frameCount = myImage.GetFrameCount(dimension);

Now, that you know the frame count of the image, you can call SelectActiveFrame by passing in the dimension and the frame index (zero based).


myImage.SelectActiveFrame(dimension,1);

If the image is being viewed at runtime, then the call to SelectActiveFrame will set the current frame, and then begin to loop through again (unless it is a jpeg image). The attached sample works around this by saving the image to a MemoryStream for display – thereby capturing the one frame that is chosen.

Sample Application w/Source Code C# or VB

Permalink

You can create a Graphics object from the base bitmap, and then use this Graphics object to draw the second bitmap with a transparent color that allows the base bitmap to show through.

  Bitmap Circle = (Bitmap)Image.FromFile(@'c:\circle.bmp');
  Bitmap MergedBMP = (Bitmap)Image.FromFile(@'c:\cross.bmp');
  Graphics g = Graphics.FromImage(Circle); 
  MergedBMP.MakeTransparent(Color.White);
  g.DrawImage(MergedBMP,0,0);
  g.Dispose();

  pictureBox1.Image = Circle;

Permalink

You can download a working project. Below are VB code snippets showing how you might do these tasks.

’load a bitmap from an embedded resource
Dim Bmp As Bitmap 
’ from an embedded resource
Dim curName As String = ''BitmapVB.sync.bmp''
Dim strm As System.IO.Stream = Me.GetType().Assembly.GetManifestResourceStream(curName)
Bmp = New Bitmap(strm)
PictureBox1.Image = Bmp
.....
.....
’load a bitmap from a file
Dim Bmp As Bitmap = Image.FromFile(''c:\sync.bmp'')
PictureBox1.Image = Bmp
.....
.....
’modify a bitmap
Dim Bmp As Bitmap = PictureBox1.Image.Clone
Dim g As Graphics = Graphics.FromImage(Bmp)
Dim brush1 As SolidBrush = New SolidBrush(Color.Red)
g.DrawString(TextBox1.Text, TextBox1.Font, brush1, 10, 10)
PictureBox2.Image = Bmp
g.Dispose()
....
....
’save a bitmap as a file
Dim dlg As SaveFileDialog = New SaveFileDialog()
dlg.Title = ''Save BMP file''
dlg.InitialDirectory = ''c:\''
dlg.Filter = ''bmp files (*.bmp)|*.bmp|All files (*.*)|*.*''
If dlg.ShowDialog = DialogResult.OK Then
      PictureBox2.Image.Save(dlg.FileName
End If
Permalink

The following method will draw a shadow of the supplied image at the specified
location.

The general usage pattern is to call this method first to draw a shadow at a

(2,2) offset from where the original image will be drawn and then draw the

original image itself.


public static void DrawShadow(Graphics g, Image iconImage, int left, int top)
{
	ImageAttributes ia = new ImageAttributes();
	ColorMatrix cm = new ColorMatrix();
			
	cm.Matrix00 = 0;
	cm.Matrix11 = 0;
	cm.Matrix22 = 0;
	cm.Matrix33 = 0.25f;
			
	ia.SetColorMatrix(cm);
	
	g.DrawImage(iconImage, new Rectangle(left, top, iconImage.Width, 

iconImage.Height), 0, 0, iconImage.Width, iconImage.Height,
		GraphicsUnit.Pixel, ia);
}
Permalink

You can simply specify the new size in the Bitmap constructor as follows:


[C#]
Bitmap bmp = new Bitmap('exisiting.bmp');
// Create a new bitmap half the size:
Bitmap bmp2 = new Bitmap(bmp, bmp.Width*0.5, bmp.Height*0.5);
this.BackgroundImage = bmp2;

[VB.Net]
Dim bmp As New Bitmap( 'exisiting.bmp')
’ Create a new bitmap half the size:
Dim bmp2 As New Bitmap( bmp, bmp.Width * 0.5, bmp.Height * 0.5)
Me.BackgroundImage = bmp2

If you have to specify a particular Interpolation mode while resizing use the following code:


[C#]
Bitmap bmp = new Bitmap('exisiting.bmp');
// Create a new bitmap half the size:
Bitmap bmp2 = new Bitmap( bmp.Width*0.5, bmp.Height*0.5, Imaging.PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bmp2);

// Set interpolation mode
g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

// Draw image using specified interpolation mode.
g.DrawImage(bmp, 0, 0, bmp2.Width, bmp2.Height);
this.BackgroundImage = bmp2

[VB.Net]
Dim bmp As New Bitmap( 'existing.bmp')
Dim bmp2 As New Bitmap( bmp.Width * 0.5, bmp.Height * 0.5, Imaging.PixelFormat.Format24bppRgb)
Dim g As Graphics = Graphics.FromImage(bmp2)

’ Set interpolation mode
g.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic

’ Draw image using specified interpolation mode.
g.DrawImage(bmp, 0, 0, bmp2.Width, bmp2.Height)
Me.BackgroundImage = bmp2
Permalink

The trick is to use an alpha component while drawing the image.


// transparency should be in the range 0 to 1
protected void DrawScrollImage(Graphics g, Rectangle rect, Image image, float transparency)
{
	ImageAttributes ia = new ImageAttributes(); 
	ColorMatrix cm = new ColorMatrix(); 
	cm.Matrix00 = 1; 
	cm.Matrix11 = 1; 
	cm.Matrix22 = 1; 
	cm.Matrix33 = transparency; 
 
	ia.SetColorMatrix(cm); 

	g.DrawImage(image, rect, 0, 0, image.Width, image.Height, 
		GraphicsUnit.Pixel, ia); 
}
Permalink

This code depends on the actual bitmap in use. This logic sets a random rectangular portion in the image to a new color.


public class ImageUtil
{
    private Image baseImage;

    private void InitBaseImage(Image baseImage)
    {
        this.baseImage = baseImage.Clone() as Image;
    }

    private Image ApplyNewColorOnImage(Color newColor)
    {
        // Create a new bitmap off the base image. 
        Image newImage = this.baseImage.Clone() as Image;
        Bitmap newBitmap = new Bitmap(newImage);

        // Set the Color cue pixels to the appropriate color. 
        // This logic of course, depends on the actual bitmap. 
        for (int i = 12; i <= 14; i++)
        for (int j = 2; j <= 14; j++)
            newBitmap.SetPixel(j, i, newColor);

        return newImage;
    }
}
Permalink

You can use the GetThumbnailImage method to generate and display a thumbnail of a bitmap as shown below:


[C#]

public bool ThumbnailCallback()
{
	return false;
}

//Generate a thumbnail of the bitmap and display it in a PictureBox

Image.GetThumbnailImageAbort myCallback =
new Image.GetThumbnailImageAbort(ThumbnailCallback);
Bitmap myBitmap = new Bitmap('C:\\images\\MyBitMap.bmp');
this.pictureBox1.Image = (Bitmap) myBitmap.GetThumbnailImage(150,75,myCallback, IntPtr.Zero);
Permalink

Since .NET uses it’s own format that is not compatible with the EnhancedMetafile format you will have to use reflection to achieve this.
(From a posting in the microsoft.public.dotnet.framework.drawing newsgroup)


[C#]
using System.Runtime.InteropServices;
using System.Reflection;


public const uint CF_METAFILEPICT = 3;
public const uint CF_ENHMETAFILE = 14;

[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool OpenClipboard(IntPtr hWndNewOwner);

[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool CloseClipboard();

[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr GetClipboardData(uint format);

[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool IsClipboardFormatAvailable(uint format);


//Pasting into PictureBox
if (OpenClipboard(this.Handle))

{
	if (IsClipboardFormatAvailable(CF_ENHMETAFILE))
	{
		IntPtr ptr = GetClipboardData(CF_ENHMETAFILE);
		if (!ptr.Equals(new IntPtr(0)))
		{
			Metafile metafile = new Metafile(ptr,true);
			//Set the Image Property of PictureBox
			this.pictureBox1.Image = metafile;
		}
	}
	CloseClipboard();
}
Permalink

This is quite simple actually. All you need to do is determine the color of a given pixel, and then subtract the RGB values from 255 (the maximum) and then reset the pixel.

Here is the pertinent code.

[Code - C#]

for(int x = 0; x < mybitmap.Width; x++)
{
	for(int y = 0; y < mybitmap.Height; y++)
	{
		//get the current color of the pixel
		System.Drawing.Color c = mybitmap.GetPixel(x,y);
				
		mybitmap.SetPixel(x,y, System.Drawing.Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
	}
}

Note: This modifies the existing image, so work on a copy if you want to maintain the original.

Permalink

This is quite simple actually. All you need to do is determine the color of a given pixel, and then subtract the RGB values from 255 (the maximum) and then reset the pixel.

Here is the pertinent code.

[Code – C#]


for(int x = 0; x < mybitmap.Width; x++)
{
	for(int y = 0; y < mybitmap.Height; y++)
	{
		//get the current color of the pixel
		System.Drawing.Color c = mybitmap.GetPixel(x,y);
				
		mybitmap.SetPixel(x,y, System.Drawing.Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
	}
}

Note: This modifies the existing image, so work on a copy if you want to maintain the original.

Permalink

You can import the BitBlt API to handle this problem. Here is a solution offered by Simon Murrell and Lion Shi in the microsoft.public.dotnet.windows.forms newsgroup. The number used below, 13369376, is Int32 SRCCOPY = 0xCC0020;


You can use Gdi32 dll. You can define the BitBlt method found within the Gdi32 dll with the code below.

[System.Runtime.InteropServices.DllImportAttribute('gdi32.dll')]
private static extern bool BitBlt(
	ntPtr hdcDest, // handle to destination DC
	int nXDest,  // x-coord of destination upper-left corner
	int nYDest,  // y-coord of destination upper-left corner
	int nWidth,  // width of destination rectangle
	int nHeight, // height of destination rectangle
	IntPtr hdcSrc,  // handle to source DC
	int nXSrc,   // x-coordinate of source upper-left corner
  	int nYSrc,   // y-coordinate of source upper-left corner
	System.Int32 dwRop  // raster operation code
);

And you can then use the copy below in a button click event to save the form to an image.

	Graphics g1 = this.CreateGraphics();
	Image MyImage = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height, g1);
	Graphics g2 = Graphics.FromImage(MyImage);
	IntPtr dc1 = g1.GetHdc();
	IntPtr dc2 = g2.GetHdc();
	BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
	g1.ReleaseHdc(dc1);
	g2.ReleaseHdc(dc2);
	MyImage.Save(@'c:\Captured.bmp', ImageFormat.Bmp);

You will need to use the System.Drawing.Imaging namespace.

Here is VB code posted by Armin Zingler in the microsoft.public.dotnet.languages.vb newsgroup.


Public Class Win32

	Public Declare Function BitBlt Lib 'gdi32' Alias 'BitBlt' _
		(ByVal hDestDC As Integer, ByVal x As Integer, _
		ByVal y As Integer, ByVal nWidth As Integer, _
		ByVal nHeight As Integer, ByVal hSrcDC As Integer, _
		ByVal xSrc As Integer, ByVal ySrc As Integer, _
		ByVal dwRop As Integer) As Integer


	Public Declare Function GetWindowDC Lib 'user32' Alias 'GetWindowDC' _
		(ByVal hwnd As Integer) As Integer

	Public Declare Function ReleaseDC Lib 'user32' Alias 'ReleaseDC' _
		(ByVal hwnd As Integer, ByVal hdc As Integer) As Integer

	Public Const SRCCOPY As Integer = &HCC0020

End Class

Public Class Hardcopy

	Public Shared Function CreateBitmap( _
			ByVal Control As Control) _
			 As Bitmap

		Dim gDest As Graphics
		Dim hdcDest As IntPtr
		Dim hdcSrc As Integer
		Dim hWnd As Integer = Control.Handle.ToInt32

		CreateBitmap = New Bitmap(Control.Width, Control.Height)
		gDest = gDest.FromImage(CreateBitmap)

		hdcSrc = Win32.GetWindowDC(hWnd)
		hdcDest = gDest.GetHdc

		Win32.BitBlt( _
			hdcDest.ToInt32, 0, 0, Control.Width, Control.Height, _
 			hdcSrc, 0, 0, Win32.SRCCOPY _
			 )

 		gDest.ReleaseHdc(hdcDest)
	 	Win32.ReleaseDC(hWnd, hdcSrc)

	End Function

End Class

’In your Form:

Private Sub Button1_Click( _
		ByVal sender As System.Object, _
		ByVal e As System.EventArgs) _
		Handles Button1.Click

	Dim bmp As Bitmap

	bmp = Hardcopy.CreateBitmap(Me)
	bmp.Save('c:\test.bmp')

End Sub
Permalink

Here is some code:


// Not the closest grayscale representation in the RGB space, but
// pretty close.
// Closest would be the cubic root of the product of the RGB colors,
// but that cannot be represented in a ColorMatrix.
public void DrawGrayedImage(Graphics g, Image image, int left,
	int top)
{ 
	ImageAttributes ia = new ImageAttributes(); 
	ColorMatrix cm = new ColorMatrix(); 

	// 1/3 on the top 3 rows and 3 columns
	cm.Matrix00 = 1/3f; 
	cm.Matrix01 = 1/3f; 
	cm.Matrix02 = 1/3f; 
	cm.Matrix10 = 1/3f; 
	cm.Matrix11 = 1/3f; 
	cm.Matrix12 = 1/3f; 
	cm.Matrix20 = 1/3f; 
	cm.Matrix21 = 1/3f; 
	cm.Matrix22 = 1/3f; 

	ia.SetColorMatrix(cm); 

	g.DrawImage(image, new Rectangle(left, top, image.Width, 
		image.Height), 0, 0, image.Width, image.Height, 
		GraphicsUnit.Pixel, ia); 
} 
Permalink
	Icon icoClose;

	// Initialize this icoClose from the resource (for example). Code omitted.
	… … …
	// Now create a new icon off this base icon with the required size (18 X 18) in this case.
	Icon icoClose18By18 = new Icon(icoClose, 18, 18);
	// Create a bitmap off this icon.
	Bitmap bmpClose = icoClose.ToBitmap();
Permalink

You use ImageAttributes, adding a ColorMap that swaps the colors. Here is a code snippet.

	Bitmap originalBMP = (Bitmap) Image.FromFile(@'c:\circle.bmp');

	//make a copy so original will still be available
	Bitmap swappedBMP = new Bitmap(originalBMP); 

	Graphics g = Graphics.FromImage(swappedBMP);
               
	// Create a color map.
	ColorMap[] colorSwapper= new ColorMap[2];
	colorSwapper[0] = new ColorMap();
	colorSwapper[1] = new ColorMap();
	colorSwapper[0].OldColor = Color.Red; //red changes to yellow
	colorSwapper[0].NewColor = Color.Yellow;
	colorSwapper[1].OldColor = Color.Blue;//blue changes to green
	colorSwapper[1].NewColor = Color.Green;
			
	// Create an ImageAttributes object, and call SetRemapTable
	ImageAttributes imageAttr = new ImageAttributes();
	imageAttr.SetRemapTable(colorSwapper);
    
	//overdraw the bitmap with swapped colors
	g.DrawImage(swappedBMP, new Rectangle(0, 0, 
		swappedBMP.Width, swappedBMP.Height),0, 0, swappedBMP.Width, 
		swappedBMP.Height, GraphicsUnit.Pixel, imageAttr);
			
	pictureBox1.Image = swappedBMP;

Here is similar code that wraps this technique in a method that swaps a single color.

	protected void DrawMyBitmap(Graphics gph, Color oldColor, Color newColor, Bitmap baseImage, Rectangle rect)
	{
		ImageAttributes imgattr = new ImageAttributes();
		ColorMap[] clrmap = new ColorMap[1]{ new ColorMap() };

		clrmap[0].OldColor = oldColor;
		clrmap[0].NewColor = newColor;				

		imgattr.SetRemapTable(clrmap);				

		gph.DrawImage(baseImage,rect,0,0,rect.Width, rect.Height,GraphicsUnit.Pixel,imgattr);
	}
Permalink

Share with

Couldn't find the FAQs you're looking for?

Please submit your question and answer.