Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ASP.NET Transparent GIF

2.23/5 (4 votes)
4 Sep 2007CPOL2 min read 1   193  
Writing a transparent GIF directly into the output stream via ASP.NET and C#.

Screenshot - transparent-gif.jpg

Introduction

Writing images into the output stream of an HTTP-Response is a simple task. Writing a transparent GIF into the output stream is not. The reason is the GDI+ handler for saving the image data to the output stream. Here is a workaround.

Background

Webmasters need some cool tools to maintain their websites and keep on track to get their business better. That's why many of these webmasters have something like Google Analytics running to track user behaviour and to track where the surfers come from (e.g., search strings via Google, referrers, natural type-ins, etc).

For some reasons, a customer of mine wasn't happy with using Google Analytics, because of two main reasons:

  1. The use of JavaScript was against their policies.
  2. The data Google Analytics gets is property of Google Inc.

So they needed a small and simple tracking solution that works without JavaScript and covers their needs.

Using the Code

To track referrers, you need to have an application that can be requested. Because of Corporate Design issues, the response of the request should be a transparent image - so a transparent GIF was exactly what I needed.

I prepared a transparent GIF and tried the following:

VB
Bitmap bm = new Bitmap(Server.MapPath("transparent.gif")); 
Response.ContentType = "image/gif";
bm.Save(Response.OutputStream, ImageFormat.Gif);
bm.Dispose();
Response.Flush();

Well, this didn't work. The image delivered to the output stream was black. Then I played a little with:

VB
bm.MakeTransparent(Color.Transparent);

But this didn't work, too. My thought was that my prepared GIF was broken, so I created a clean black GIF and tried to use MakeTransparent(Color.Black), but with no success.

Solution

VB
System.Drawing.Image _gifImage;

_gifImage = System.Drawing.Image.FromFile(Server.MapPath("white.JPG"));
Bitmap bm = new Bitmap(_gifImage.Width, _gifImage.Height, 
        PixelFormat.Format8bppIndexed);

// Get the palette from the bitmap
ColorPalette pal = bm.Palette;

// Set Alpha to 0
for (int i = 0; i < pal.Entries.Length; i++)
{
    Color col = pal.Entries[i];
    pal.Entries[i] = Color.FromArgb(0, col.R, col.G, col.B);
}

// assign palette
bm.Palette = pal;

//to copy the bitmap data we need to lock the source & 
//destination bits
BitmapData src = ((Bitmap)_gifImage).LockBits(new Rectangle
(0, 0, _gifImage.Width, _gifImage.Height), ImageLockMode.ReadOnly,
 _gifImage.PixelFormat);
BitmapData dst = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), 
ImageLockMode.WriteOnly, bm.PixelFormat);

//finished, unlock the bits
((Bitmap)_gifImage).UnlockBits(src);
bm.UnlockBits(dst);

//Set Response Type to "image/gif"
Response.ContentType = "image/gif";

//Writing the gif directly into the Output-Stream
bm.Save(Response.OutputStream, ImageFormat.Gif);

//cleaning up
bm.Dispose();
_gifImage.Dispose();

//Send output stream
Response.Flush(); 

In short, we're creating a new color palette for our GIF. Then, we're changing all the Alpha entries to zero - the GIF encoder will now encode the transparent color for every entry that has Alpha == 0.

Points of Interest

The Bitmap.Save() method promotes the format of the GIF to 32 bpp before giving the image to the GIF-encoder. The GIF-encoder color-reduces it to a 256-entry color table. When the dynamically generated image format is at 8 bpp, the GIF-encoder just encodes its palette entries into the smallest GIF color table possible. And, this exactly is the problem in here.

Links & Resources

History

  • 2007/04/09: Initial publishing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)