Generating a transparent GIF image using C#
Problem:
There is apparently no easy way to generate a transparent GIF image using the .NET framework. Microsoft provided a method in the Bitmap class called MakeTransparent() but it doesn’t work for GIFs, it only seems to work for PNGs.
To create a transparent GIF you need to recreate the color table of the image using Imaging APIs, as detailed in this KB article . Unfortunately, this can be pretty slow for an ASP.NET Web application, and it has a lot of overhead, so I needed an alternative.
Solution:
The alternative is to alter the color table directly using the GIF specification. To implement this, I needed to save the non-transparent GIF to a MemoryStream, and then go through the binary data, updating the color table with the new transparency bits.
The original code for this function is not my own, I have found it somewhere on the Internet and modified it. Unfortunately I can’t remember where I found it, so I can’t give credit, but if you know the original author please add a comment.
Source:
MemoryStream fin = new MemoryStream(); bitmap.Save(fin, System.Drawing.Imaging.ImageFormat.Gif); MemoryStream fout = new MemoryStream((int)fin.Length); int count = 0; byte[] buf = new byte[256]; byte transparentIdx = 0; fin.Seek(0, SeekOrigin.Begin); //header count = fin.Read(buf, 0, 13); if ((buf[0] != 71) || (buf[1] != 73) || (buf[2] != 70)) return null; //GIF fout.Write(buf, 0, 13); int i = 0; if ((buf[10] & 0×80) > 0) { i = 1 << ((buf[10] & 7) + 1) == 256 ? 256 : 0; } for (; i != 0; i—) { fin.Read(buf, 0, 3); if ((buf[0] == R) && (buf[1] == G) && (buf[2] == B)) { transparentIdx = (byte)(256 – i); } fout.Write(buf, 0, 3); } bool gcePresent = false; while (true) { fin.Read(buf, 0, 1); fout.Write(buf, 0, 1); if (buf[0] != 0×21) break; fin.Read(buf, 0, 1); fout.Write(buf, 0, 1); gcePresent = (buf[0] == 0xf9); while (true) { fin.Read(buf, 0, 1); fout.Write(buf, 0, 1); if (buf[0] == 0) break; count = buf[0]; if (fin.Read(buf, 0, count) != count) return null; if (gcePresent) { if (count == 4) { buf[0] |= 0×01; buf[3] = transparentIdx; } } fout.Write(buf, 0, count); } } while (count > 0) { count = fin.Read(buf, 0, 1); fout.Write(buf, 0, 1); } fin.Close(); fout.Flush(); return new Bitmap(fout); }Download ASP.NET GIF Transparency Demo WebForm
[tags]C#, GIF, Transparent GIF, ASP.NET, Bitmap, System.Graphics[/tags]
on October 18th, 2007 at 5:56 am
Hi Andrei,
Great Posting thank you very much for sharing this info.
Although the code published has some syntaxes problems and a extra almost at the beginning.
Referring to this topic, I think you are generating GIFs because you want to display transparent images on the a browser and IE6 is not a good player with PNG.
An alternative would be to let .NET generate a PNG8 that’s well accepted by IE4 onwards!
But I couldn’t find a why to make the .NET framework do it, do you know if that’s possible?
Best regards,
Vladimir
on February 6th, 2008 at 12:16 pm
Dear Andrei,
This is excellent! You save me a lot of time, not to mention those hours what I spent searching for such a "converter". I’m developing a web application, where I use a lot of transparent images, but I have to use the png format (because of the Graphics.FromImage function – isn’t able to populate Graphics object from image with indexed format, like gif). Of course, our wonderful browser (let’s call it "ie6.0"), doesn’t support transparent png, only with alphaimageloader, but it isn’t so fast. With this function, I can create gif-s for mozilla and for explorer too from the png files I create. This is the solution for me! So, you rock!
Thanks a lot!
Best regards,
Csiga
on March 7th, 2008 at 6:56 am
Dear Andrei,
Thank you very much! Your article give me a very usedly help.
In order to resovle this issue,I had searched all forums,BBS,Tech. Blog in China almost,but can’t get a best solution yet,so much as I had make a decision to give up it.
Thanks!
Best regards,
Kim
on May 25th, 2008 at 4:54 pm
Could someone please post the code without any syntax errors.
Thanks
on June 12th, 2008 at 5:38 pm
I’m wondering wouldn’t be easer to convert GIF to PNG, then use .NET function foradding transparency, then convert PNG back to the GIF?
Or it’s not working?
on July 3rd, 2008 at 1:28 pm
Here is the code w/o syntax errors.
//
///
/// Returns a transparent background GIF image from the specified Bitmap.
///
/// The Bitmap to make transparent.
/// The Color to make transparent.
/// New Bitmap containing a transparent background gif.
public Bitmap MakeTransparentGif(Bitmap bitmap, Color color)
{
byte R = color.R;
byte G = color.G;
byte B = color.B;
MemoryStream fin = new MemoryStream();
bitmap.Save(fin, System.Drawing.Imaging.ImageFormat.Gif);
MemoryStream fout = new MemoryStream((int)fin.Length);
int count = 0;
byte[] buf = new byte[256];
byte transparentIdx = 0;
fin.Seek(0, SeekOrigin.Begin);
//header
count = fin.Read(buf, 0, 13);
if ((buf[0] != 71) || (buf[1] != 73) || (buf[2] != 70)) return null; //GIF
fout.Write(buf, 0, 13);
int i = 0;
if ((buf[10] & 0×80) > 0)
{
i = 1 < ((buf[10] & 7) + 1) == 256 ? 256 : 0;
}
for (; i != 0; i—)
{
fin.Read(buf, 0, 3);
if ((buf[0] == R) && (buf[1] == G) && (buf[2] == B))
{
transparentIdx = (byte)(256 – i);
}
fout.Write(buf, 0, 3);
}
bool gcePresent = false;
while (true)
{
fin.Read(buf, 0, 1);
fout.Write(buf, 0, 1);
if (buf[0] != 0×21) break;
fin.Read(buf, 0, 1);
fout.Write(buf, 0, 1);
gcePresent = (buf[0] == 0xf9);
while (true)
{
fin.Read(buf, 0, 1);
fout.Write(buf, 0, 1);
if (buf[0] == 0) break;
count = buf[0];
if (fin.Read(buf, 0, count) != count) return null;
if (gcePresent)
{
if (count == 4)
{
buf[0] |= 0×01;
buf[3] = transparentIdx;
}
}
fout.Write(buf, 0, count);
}
}
while (count > 0)
{
count = fin.Read(buf, 0, 1);
fout.Write(buf, 0, 1);
}
fin.Close();
fout.Flush();
return new Bitmap(fout);
}
//
on October 23rd, 2008 at 12:14 pm
i think the orginial author of the code can be found here:
http://www.ben-rush.net/blog/PermaLink.aspx?guid=103ed74d-c808-47ba-b82d-6e9367714b3e&dotnet=consultant
on October 24th, 2008 at 12:05 pm
Thanks for this! Just what I was looking for. Nice job to whomever created it.
A slight change is required if a color exists twice within a gif color map. I changed the declaration of the transparent index to :
byte? transparentIdx = null;
Then altered the for loop that searched for the index:
for (; i != 0; i—)
{
fin.Read(buf, 0, 3);
if ((buf[0] == R) && (buf[1] == G) && (buf[2] == B))
{
if (transparentIdx == null)
transparentIdx = (byte)(256 – i);
}
fout.Write(buf, 0, 3);
}
if (transparentIdx == null)
transparentIdx = 0;
Finally, I changed the assignment at the bottom to convert the nullable index to a standard byte.
if (count == 4)
{
buf[0] |= 0×01;
buf[3] = (byte)transparentIdx;
}
Again, thanks!
on February 13th, 2009 at 1:14 am
I have had success in creating transparent GIFs in ASP.NET. In my code sample I added a hack for forcing GIF transparency and work around the .NET limitation of a pre-defined non-transparent palette. Have a look at this article:
http://911-need-code-help.blogspot.com/2009/02/create-text-images-on-fly-with-aspnet.html
on August 11th, 2009 at 12:47 pm
Complete code is useless, and only usefull for those whom have a fix requirements.
on June 1st, 2010 at 5:21 pm
this code doesn’t work. it doesn’t pick a transparent color in any way that uses at least a bit inteligence, so it’s quite useless…
.on June 1st, 2010 at 6:18 pm
to add:
this algorithm recognizes only colors with the same rgb.
on August 13th, 2010 at 7:12 pm
Thanks again, the source code you posted is very helpful!
on August 26th, 2010 at 7:21 am
Thanks for such a great post and the review, I am totally impressed! Keep stuff like this coming.
on August 30th, 2010 at 1:43 am
very cool post
on August 30th, 2010 at 10:01 pm
Perhaps this is one of the most interesting blogs that I have ever seen. Interesting article, Funny comment. Keep it up!
on August 31st, 2010 at 8:41 am
I didn’t know about this. Wow, it has been an eye-opener. So glad to have stumbled upon this.