|
I've tried settign a value for the transparency but no matter what I do it doesn't work. I noticed that the FindClosest function called in Save() was beign called before the Analyze function. I updated the code so that FindClosest now returns what looks like an accurate index as far as I can tell but when I look at th eGif in IE then the transparency is not showing (excuse the 'pun') and in a Gif editor the transparency is not set.
Has anyone else tried using the transparency in this? I really want to avoid sitting down and reading the enitre Gif Spec to understand this!
Thanks in advance
Jim
|
|
|
|
|
Hi,
I have found this problem. To fix it:
edit file AnimatedGifEncoder.cs, at the end of the method AnalyzePixels(), comment Findcloasest, instead, using nq.Map:
// transIndex = FindClosest(transparent);
transIndex = nq.Map(transparent.B, transparent.G, transparent.R);
It will work.
I also fixed a number of other bugs in GifDecoder.cs. I want to post the whole package up, but don't know how.
Adam
|
|
|
|
|
Hi
Can you please email the complete code at angel1241@hotmail.com?
Thanks
A
|
|
|
|
|
Hi Chuanchu:
Could you please also send me a copy of your bug-fixing copy. I will appreciate it very much!
Jeff Tan
x.tan@hotmail.com
|
|
|
|
|
i tried this.
I am facing problem with transparent images in decoding itself(while splitting)
I am geting the first frame with transparent background but the rest is geting a black background
|
|
|
|
|
Hi,
Your fix so nearly almost worked! The bottom-right pixel of the resulting animation appears to flicker through a selection of colours. Any ideas on how to fix this?
Edit: I've just also noticed parts of the image becoming transparent which weren't originally transparent. I'm guessing this is something to do with the colour of those parts matching the transparency colour. Does this mean having to write an algorithm to find an unused colour in all frames prior to adding them?
|
|
|
|
|
Nope. Still doesn't work. Anyone find a solution to this problem?
|
|
|
|
|
hello can you please email me updated bugs free file of this example on my email id ..its arpit@sleexs.com
Thank you in advance
|
|
|
|
|
I have use the code on the Net CF 1.0. and Found it does not pharse the gif file well.
When I fixed the follow code, it work well now.
I just modify the function GetPixels in the file GifDecoder
int [] GetPixels( Bitmap bitmap )
{
//int [] pixels = new int [ 3 * image.Width * image.Height ]; //Orginal
int[] pixels = new int[3 * image.Width * image.Height]; //Modified
int count = 0;
for (int th = 0; th < image.Height; th++)
{
for (int tw = 0; tw < image.Width; tw++)
{
Color color = bitmap.GetPixel(tw, th);
// pixels[count] = color.R; //Orginal
// count++; //Orginal
// pixels[count] = color.G;//Orginal
// count++;//Orginal
// pixels[count] = color.B;//Orginal
pixels[count] = color.ToArgb(); //Added
count++;
}
}
return pixels;
Would anyone please confirm it?
|
|
|
|
|
Good work. However this line should be
//int[] pixels = new int[3 * image.Width * image.Height]; //Modified
int[] pixels = new int[image.Width * image.Height]; // New Modified
|
|
|
|
|
|
I looked all over the NET. This by far is the only good enough solution I see (even in April 2007) -- full 2 years after this article was written.
The only thing I would want to change in this code would be to optimize for speed and size; nothing else!
|
|
|
|
|
I have been able to optimize the GifDecoder quiet a bit, but at the expense of compatability. The realy slow code which runs a lot (realy A LOT) of times is the GetPixel() and SetPixel() functions. I have rewritten the code to avoid the use of those, but this have to be done in "usafe" context. This means that you have to compile with the compiler option "unsafe", and that the executable will only run on the processor type you compiled it on (afair). You can just replace the two functions below in the GifDecoder.cs file.
Here is the code for the GetPixels function
int [] GetPixels( Bitmap bitmap )
{
int [] pixels = new int [ 3 * image.Width * image.Height ];
int count = 0;
int tw, th;
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
int scanwidth = data.Stride;
System.IntPtr Scan = data.Scan0;
int width = bitmap.Width;
int height = bitmap.Height;
unsafe
{
int offset;
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
bitmap.PixelFormat == PixelFormat.Format32bppPArgb ||
bitmap.PixelFormat == PixelFormat.Format32bppRgb)
{
offset = scanwidth - bitmap.Width * 4;
}
else
offset = scanwidth - bitmap.Width * 3;
int x, y;
byte colr, colg, colb;
byte* p = (byte*)(void*)Scan;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
pixels[count++] = (int)*(p++);
pixels[count++] = (int)*(p++);
pixels[count++] = (int)*(p++);
}
p += offset;
}
}
bitmap.UnlockBits(data);
return pixels;
}
Here is the code for the SetPixels function
void SetPixels( int [] pixels )
{
int count = 0;
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
int scanwidth = data.Stride;
System.IntPtr Scan = data.Scan0;
int width = image.Width;
int height = image.Height;
unsafe
{
bool fourBytePerPixel = false;
int offset;
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
bitmap.PixelFormat == PixelFormat.Format32bppPArgb ||
bitmap.PixelFormat == PixelFormat.Format32bppRgb)
{
offset = scanwidth - bitmap.Width * 4;
fourBytePerPixel = true;
}
else
offset = scanwidth - bitmap.Width * 3;
int x, y;
byte* p = (byte*)(void*)Scan;
Int32 pixeldata;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
pixeldata = pixels[count++];
*(p++) = (byte)(pixeldata);
*(p++) = (byte)(pixeldata >> 8);
*(p++) = (byte)(pixeldata >> 16);
if (fourBytePerPixel)
*(p++) = (byte)(pixeldata >> 24);
}
p += offset;
}
}
bitmap.UnlockBits(data);
}
You must have me excused if the code is a bit cluttered, but it should be usefull anyway. Actually I have not gone into details to see whether it is necessary to test for 24 or 32 bit images, as the code might use purly 32 bit images.
- Lothver
|
|
|
|
|
Has anyone been able to optimize this code for the encoder?
I have 15 frames which amount to 82kb, however if I use a animated gif application its only 38kb, something isn't right?
modified 19-Aug-21 21:01pm.
|
|
|
|
|
Do you mean size optimization such that the resulting GIF file is smaller?
- Lothver
|
|
|
|
|
Yeah
I've managed to do it now
modified 19-Aug-21 21:01pm.
|
|
|
|
|
Any possibility of sharing your optimisations?
Thanks
|
|
|
|
|
Do you know how I can play a gif in a Form?
_____________________________
...and justice for all
APe
|
|
|
|
|
|
Just FYI
This will violate LZW Patent No. 4,558,302 by Unisys.
Compuserve hold copyright on the GIF89a but the compression used for the images internaly is LZW.
Schneider
Schneider
|
|
|
|
|
I am no lawyer, but I think the patent expired few years ago...
|
|
|
|
|
It did a few YEARS ago
So png freaks put a cap on it
|
|
|
|
|
Feature request number 1 on my pet project, www.foodcandy.com after its launch six months ago was that there're no animated gifs supported on the site. I now have it working! It should go live next week. So many thanks for this code. If someone maintains an open source version I'll be glad to contribute pieces.
|
|
|
|
|
Default loop count should be -1 (don't loop), 1 means loop once (animate twice).
|
|
|
|
|
I think that forcing the GIF to crop is not very nice Here's a change to resize the GIF frames to whatever the target (or first frame) size is.
<br />
private static Image GetResizedImage(Image imgPhoto, Size ts)<br />
{<br />
<br />
int sourceWidth = imgPhoto.Width;<br />
int sourceHeight = imgPhoto.Height;<br />
int sourceX = 0;<br />
int sourceY = 0;<br />
int destX = 0;<br />
int destY = 0;<br />
<br />
float nPercent = 0;<br />
float nPercentW = 0;<br />
float nPercentH = 0;<br />
<br />
bool sourceVertical = sourceWidth < sourceHeight;<br />
bool targetVeritcal = ts.Width < ts.Height;<br />
<br />
if (sourceVertical != targetVeritcal)<br />
{<br />
int t = ts.Width;<br />
ts.Width = ts.Height;<br />
ts.Height = t;<br />
}<br />
<br />
nPercentW = ((float)ts.Width / (float)sourceWidth);<br />
nPercentH = ((float)ts.Height / (float)sourceHeight);<br />
if (nPercentH < nPercentW)<br />
{<br />
nPercent = nPercentH;<br />
destX = System.Convert.ToInt16((ts.Width -<br />
(sourceWidth * nPercent)) / 2);<br />
}<br />
else<br />
{<br />
nPercent = nPercentW;<br />
destY = System.Convert.ToInt16((ts.Height -<br />
(sourceHeight * nPercent)) / 2);<br />
}<br />
<br />
int destWidth = (int)(sourceWidth * nPercent);<br />
int destHeight = (int)(sourceHeight * nPercent);<br />
<br />
Bitmap bmPhoto = new Bitmap(ts.Width, ts.Height,<br />
PixelFormat.Format24bppRgb);<br />
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,<br />
imgPhoto.VerticalResolution);<br />
<br />
Graphics grPhoto = Graphics.FromImage(bmPhoto);<br />
grPhoto.Clear(Color.White);<br />
grPhoto.InterpolationMode =<br />
InterpolationMode.HighQualityBicubic;<br />
<br />
grPhoto.DrawImage(imgPhoto,<br />
new Rectangle(destX, destY, destWidth, destHeight),<br />
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),<br />
GraphicsUnit.Pixel);<br />
<br />
grPhoto.Dispose();<br />
return bmPhoto;<br />
}<br />
<br />
protected void GetImagePixels()<br />
{<br />
int w = image.Width;<br />
int h = image.Height;<br />
if ((w != width)<br />
|| (h != height)<br />
)<br />
{<br />
image = GetResizedImage(image, new Size(width, height));<br />
}<br />
....<br />
<br />
public bool IsTransparent()<br />
{<br />
return transparency;<br />
}<br />
<br />
public Color GetTransparency()<br />
{<br />
Color c = Color.Empty;<br />
if (transparency)<br />
{<br />
c = Color.FromArgb(0, 0, 0, 0);
}<br />
else<br />
{<br />
c = Color.FromArgb(lastBgColor);<br />
}<br />
return c;<br />
}<br />
and finally the whole resize, very simple
<br />
<br />
public static void Resize(Stream inStream, Stream outStream, int width, int height)<br />
{<br />
GifDecoder decoder = new GifDecoder();<br />
decoder.Read(inStream);<br />
<br />
AnimatedGifEncoder encoder = new AnimatedGifEncoder();<br />
encoder.SetSize(width, height);<br />
encoder.SetFrameRate(5);<br />
encoder.SetRepeat(decoder.GetLoopCount());<br />
if (decoder.IsTransparent()) encoder.SetTransparent(decoder.GetTransparency());<br />
encoder.Start(outStream);<br />
for (int i = 0; i < decoder.GetFrameCount(); i++)<br />
{<br />
encoder.SetDelay(decoder.GetDelay(i));<br />
encoder.AddFrame(decoder.GetFrame(i));<br />
}<br />
encoder.Finish();<br />
outStream.Flush();<br />
}<br />
|
|
|
|