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.
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.
You can download a working project. Below are VB code snippets showing how you might do these tasks.
’load a bitmapfrom an embedded resource
Dim Bmp AsBitmap
’ from an embedded resource
Dim curName AsString = ''BitmapVB.sync.bmp''
Dim strm As System.IO.Stream = Me.GetType().Assembly.GetManifestResourceStream(curName)
Bmp = NewBitmap(strm)
PictureBox1.Image = Bmp
.....
.....
’load a bitmapfrom a file
Dim Bmp AsBitmap = Image.FromFile(''c:\sync.bmp'')
PictureBox1.Image = Bmp
.....
.....
’modify a bitmap
Dim Bmp AsBitmap = 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 bitmapas 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
EndIf
The trick is to use an alpha component while drawing the image.
// transparency should be in the range 0 to 1protectedvoidDrawScrollImage(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);
}
This code depends on the actual bitmap in use. This logic sets a random rectangular portion in the image to a new color.
publicclassImageUtil
{
private Image baseImage;
privatevoidInitBaseImage(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;
}
}
You can use the GetThumbnailImage method to generate and display a thumbnail of a bitmap as shown below:
[C#]
publicboolThumbnailCallback()
{
returnfalse;
}
//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);
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;
publicconstuint CF_METAFILEPICT = 3;
publicconstuint CF_ENHMETAFILE = 14;
[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
publicstaticexternboolOpenClipboard(IntPtr hWndNewOwner);
[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
publicstaticexternboolCloseClipboard();
[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
publicstaticextern IntPtr GetClipboardData(uint format);
[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true)]
publicstaticexternboolIsClipboardFormatAvailable(uint format);
//Pasting into PictureBoxif (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 PictureBoxthis.pictureBox1.Image = metafile;
}
}
CloseClipboard();
}
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 pixelSystem.Drawing.Colorc = 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.
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 pixelSystem.Drawing.Colorc = 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.
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 foundwithin the Gdi32 dll with the code below.
[System.Runtime.InteropServices.DllImportAttribute('gdi32.dll')]
privatestatic 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 tosource DC
int nXSrc, // x-coordinate ofsourceupper-left corner
int nYSrc, // y-coordinate ofsourceupper-left corner
System.Int32 dwRop // raster operation code
);
And you can then use the copy below in a button click eventtosave the formto 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 DeclareFunction BitBlt Lib 'gdi32'Alias'BitBlt' _
(ByVal hDestDC AsInteger, ByVal x AsInteger, _
ByVal y AsInteger, ByVal nWidth AsInteger, _
ByVal nHeight AsInteger, ByVal hSrcDC AsInteger, _
ByVal xSrc AsInteger, ByVal ySrc AsInteger, _
ByVal dwRop AsInteger) AsIntegerPublicDeclareFunction GetWindowDC Lib 'user32'Alias'GetWindowDC' _
(ByVal hwnd AsInteger) AsIntegerPublicDeclareFunction ReleaseDC Lib 'user32'Alias'ReleaseDC' _
(ByVal hwnd AsInteger, ByVal hdc AsInteger) AsIntegerPublic Const SRCCOPY AsInteger = &HCC0020
EndClassPublicClass Hardcopy
PublicSharedFunction CreateBitmap( _
ByVal Control As Control) _
AsBitmap
Dim gDest As Graphics
Dim hdcDest As IntPtr
Dim hdcSrc AsInteger
Dim hWnd AsInteger = Control.Handle.ToInt32
CreateBitmap = NewBitmap(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)
EndFunctionEndClass
’In your Form:
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Dim bmp AsBitmap
bmp = Hardcopy.CreateBitmap(Me)
bmp.Save('c:\test.bmp')
End Sub
// 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.publicvoidDrawGrayedImage(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);
}
Icon icoClose;
// Initialize this icoClose from the resource (for example). Code omitted.
… … …
// Now create a new icon off this base icon with the requiredsize (18 X 18) in this case.
Icon icoClose18By18 = new Icon(icoClose, 18, 18);
// Create a bitmapoff this icon.
Bitmap bmpClose = icoClose.ToBitmap();
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.
protectedvoidDrawMyBitmap(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);
}