Introduction
If you have an image file and need to create a reflection (left, right, above, or below) with a gradient fade out, this simple utility can help you. The C# code that does the work may help you too. If you want something more powerful, consider Gimp, which is free, very powerful, and comes with source code, but has a steep learning curve.
Background
I needed a simple utility to quickly and easily create a reflection of an image file and assumed someone had already done this. Indeed Fco. Xavier Marin had (see CodeProject ReflectionPicture
). But not being able to use it out of the box, I wrote this utility to meet my needs. It will convert a common image file which can then optionally be saved as a GIF, JPEG, PNG, TIF, etc. Others have saved me time with their submissions. This is a small submission to help offset some of my debt to the CodeProject community.
Credits
An excellent source of information on the issues related to manipulating Bitmaps can be found on BobPowell.net. There you will find detailed explanations of things like how and when to use functions like LockBits, so I will not repeat it here.
The files in this project's Images folder are the same as those in Fco. Xavier Marin ReflectionPicture
project.
Using the Code
If you have Visual Studio 2005, then you should be able to use the project source code "out of the box" -- simply build and run. It is reasonably documented. A side benefit of the code for Bitmap/Image newbies is it has simple examples of how to create a Bitmap, how to color it and change the alpha value of each pixel, etc. You can find the source code in VVX_ImageTools.cs, which is included in the project. You will undoubtedly find that you can build a better UI or write better code.
WARNING: Unsafe Code Ahead
Managed code can be used to manipulate Bitmaps. But it can be a little too slow. To get the job done a little faster, the code in VVX_ImageTools.cs uses "unsafe" code in two methods -- DoShowImageAndReflection(...)
and DoConvertToFormat32bppArgb(...)
-- with the code marked as unsafe{...}
as in the code fragment shown below.
For this code to compile in Visual Studio 2005, in the Project menu select Properties > Build and then check "Allow Unsafe Code".
Code for Converting a Bitmap to a Format32bppArgb Pixel Format
In order for gradient fade-out to work, lower resolution (i.e., less than Format32bppArgb
) files have to be upgraded. The code fragment below (found in VVX_ImageTools.cs) does the job, though you might have a better way to do it.
public bool DoConvertToFormat32bppArgb(Bitmap bmpSrc, ref Bitmap bmpTgt)
{
bool bRet = false;
try
{
PixelFormat pixFmtSrc = bmpSrc.PixelFormat;
PixelFormat pixFmtTgt = PixelFormat.Format32bppArgb;
if (pixFmtSrc != PixelFormat.Format32bppRgb)
{
int iWidth = bmpSrc.Width;
int iHeight = bmpSrc.Height;
bmpTgt = new Bitmap(bmpSrc.Width, bmpSrc.Height, pixFmtTgt);
Rectangle rc = new Rectangle(0, 0, iWidth, iHeight);
BitmapData bmdTgt = bmpTgt.LockBits(rc, ImageLockMode.ReadOnly, pixFmtTgt);
unsafe
{
int PixelSize = 4;
for (int y = 0; y < bmdTgt.Height; y++)
{
byte* row = (byte*)bmdTgt.Scan0 + (y * bmdTgt.Stride);
for (int x = 0; x < bmdTgt.Width; x++)
{
Color clr = bmpSrc.GetPixel(x, y);
int xRef = x * PixelSize;
row[xRef + 0] = clr.B;
row[xRef + 1] = clr.G;
row[xRef + 2] = clr.R;
if (mbMakeTransparent && (clr == this.mColorToMakeTransparent))
row[xRef + 3] = 0;
else
row[xRef + 3] = 255;
}
}
}
bmpTgt.UnlockBits(bmdTgt);
}
bRet = true;
}
catch (Exception ex)
{
this.msErrorMsg += this.msEOL + ex.ToString();
bRet = false;
}
return bRet;
}
Automatically Upgrades Low Resolution Images
If the source file opened is not 32-bits per pixel, i.e. ARGB compatible, the image is automatically "upgraded" using the method shown above and then saved with a modified extension. For example, if you open a 24-bit RGB image file, say test.bmp, then it will be saved as test.bmp.32bppArgb.png. The code that does this is shown below:
if (bmpReflection.PixelFormat != PixelFormat.Format32bppArgb)
{
DoConvertToFormat32bppArgb(bmpOriginal, ref bmpReflection);
if (true)
{
string sConvertedFile = msFile+".32bppArgb.png";
this.SaveAs(bmpReflection, sConvertedFile);
this.DoUpdateErrorMsg(sConvertedFile + " will work faster!");
}
bmpReflection.RotateFlip(this.menRotateFlipType);
}
This approach works best for my needs. However, if you don't like it, either change the 'true
' in the above code to 'false
' or do something that works best for you.
Code for Saving a Bitmap with Different File Types
public bool SaveBitmap(Bitmap bmp, string sOutputFilename)
{
bool bRet = false;
try
{
FileInfo fiOutputFile = new FileInfo(sOutputFilename);
ImageFormat imgFmtWant = ImageFormat.Png;
switch (fiOutputFile.Extension.ToUpper())
{
case ".BMP" : imgFmtWant = ImageFormat.Bmp; break;
case ".EMF" : imgFmtWant = ImageFormat.Emf; break;
case ".EXF" :
case ".EXIF": imgFmtWant = ImageFormat.Exif; break;
case ".GIF" : imgFmtWant = ImageFormat.Gif; break;
case ".ICO" : imgFmtWant = ImageFormat.Icon; break;
case ".JPG" :
case ".JPEG": imgFmtWant = ImageFormat.Jpeg; break;
case ".PNG" : imgFmtWant = ImageFormat.Png; break;
case ".TIF" :
case ".TIFF": imgFmtWant = ImageFormat.Tiff; break;
case ".WMF" : imgFmtWant = ImageFormat.Wmf; break;
default:
sOutputFilename += ".png";
this.DoUpdateErrorMsg("WARNING: Output file name modified;
Extension '.png' added.");
break;
}
bmp.Save(sOutputFilename, imgFmtWant);
bRet = true;
}
catch (Exception ex)
{
this.msErrorMsg += this.msEOL + ex.ToString();
bRet = false;
}
return bRet;
}
History
- 6th March, 2007: Initial post