Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Image File Reflector

0.00/5 (No votes)
6 Mar 2007 1  
A simple utility to quickly create reflected versions of an image file (*.GIF, *.PNG, etc.)
Screenshot - ImageReflector.png

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;
            // create a bitmap with the same size but desired format
            bmpTgt = new Bitmap(bmpSrc.Width, bmpSrc.Height, pixFmtTgt);

            //Ref: http://www.bobpowell.net/lockingbits.htm
            // lock all the bits
            Rectangle rc = new Rectangle(0, 0, iWidth, iHeight);
            BitmapData bmdTgt = bmpTgt.LockBits(rc, ImageLockMode.ReadOnly, pixFmtTgt);

            unsafe
            {
                //NOTE: For this to work in VS2005, in Project > Properties > Build
                // you must check "Allow Unsafe Code"
                //--- loop through each scan line and COPY each pixel from current
                //    format to desired format, e.g., Format32bppRgb 
                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++)
                    {
                        //---get the color from the source
                        Color clr = bmpSrc.GetPixel(x, y);
                        //---set color attributes in the target
                        // Each of the 4 bytes of this 32-bit pixel must be set
                        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;      // 0 is 100% transparent
                        else
                            row[xRef + 3] = 255;   // 255 is 100% opaque
                    }
                }
            }
            //now unlock all the bits we locked earlier
            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);

        //determine the image format from the file name
        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: // none of the above, so add PNG to the name
                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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here