in Education by
I have a piece of code which resizes animated gifs. if it helps the code will always resize images to a smaller size. (there's no need to make them bigger for now) I am using Atalasoft's dotimage library and their example code to do the actual resampling. The code is supposed to read an animated gif from disk, iterate through the frames and resize each frame to the new size. This works fine when the gif animation contains frames of the same size but resizing a animation with different sized frames breaks the animation (the frames don't overlap each other correctly after resizing), I think it's because the code is not computing the new offsets correctly. I think it's this line of code which is not computing the offsets right: Point point = new Point((int)(frame.Location.X * ratio), (int)(frame.Location.Y * ratio)); Here's the complete resize routine: static private void GenerateGifImage(FileStream fileStream, int OutputWidth, int OutputHeight) { // MemoryStream InputStream = new MemoryStream(); FileStream InputStream = fileStream; // fileStream.Write(InputStream.GetBuffer(), 0, (int)InputStream.Position); // InputStream.Seek(0, SeekOrigin.Begin); Image InputImage = Image.FromStream(InputStream, true, false); // this will invalidate the underlying image object in InputImage but the class properties // will still accessible until the object is disposed InputStream.Seek(0, SeekOrigin.Begin); ImageInfo imageInfo = RegisteredDecoders.GetImageInfo(InputStream); InputStream.Seek(0, SeekOrigin.Begin); GifDecoder gifDecoder = new GifDecoder(); int count = gifDecoder.GetFrameCount(InputStream); GifFrameCollection gifFrameCollection = new GifFrameCollection(); gifFrameCollection.Height = OutputHeight; gifFrameCollection.Width = OutputWidth; // gifFrameCollection.Height = gifDecoder.Frames.Height; // gifFrameCollection.Width = gifDecoder.Frames.Width; double ratio; if (InputImage.Height > InputImage.Width) { ratio = (double)OutputHeight / (double)InputImage.Height; } else { ratio = (double)OutputWidth / (double)InputImage.Width; } for (int i = 0; i < count; i++) { GifFrame frame = gifDecoder.Frames[i]; Rectangle rectangle = new Rectangle(Point.Empty, frame.Image.Size); int frameWidth = (int)(frame.Image.Width * ratio); int frameHeight = (int)(frame.Image.Height * ratio); // account for erratic rounding, seems illogical but has happened earlier when using floats instead of doubles if (frameWidth > OutputWidth) { frameWidth = OutputWidth; } if (frameHeight > OutputHeight) { frameHeight = OutputHeight; } Size size = new Size(frameWidth, frameHeight); // only resize if we have a measureable dimension if (size.Width > 0 && size.Height > 0) { // ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.NearestNeighbor); ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.NearestNeighbor); AtalaImage atalaImage = resampleCommand.Apply(frame.Image).Image; // save the image for debugging // atalaImage.Save("frame" + i.ToString() + ".gif", ImageType.Gif, null); // frame.Image.Save("frame-orig" + i.ToString() + ".gif", ImageType.Gif, null); // AtalaImage atalaImage = frame.Image; Point point = new Point((int)(frame.Location.X * ratio), (int)(frame.Location.Y * ratio)); // Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); gifFrameCollection.Add(new GifFrame(atalaImage, point, frame.DelayTime, frame.Interlaced, frame.FrameDisposal, frame.TransparentIndex, frame.UseLocalPalette)); } } FileStream saveStream = new FileStream("resized.gif", FileMode.Create, FileAccess.Write, FileShare.Write); GifEncoder gifSave = new GifEncoder(); gifSave.Save(saveStream, gifFrameCollection, null); saveStream.Close(); } JavaScript questions and answers, JavaScript questions pdf, JavaScript question bank, JavaScript questions and answers pdf, mcq on JavaScript pdf, JavaScript questions and solutions, JavaScript mcq Test , Interview JavaScript questions, JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)

1 Answer

0 votes
by
I work at Atalasoft I looked into this -- your code is absolutely right and would work on frames of unequal size just fine. The point you are calculating is correct. The problem is that in your 3 frame GIF, your second frame and third frame are precisely made to be overlaid on top of the first and use a very complex transparent mask to show the first frame through them. When your image is resampled to a new size, the mask might not be precise any more -- since you are resizing to just a one pixel difference on width and height, there is no way that this mask could match. There are several solutions to this problem Overlay frame 2 onto frame 1, then resample and use that image instead Do #1, but then extract the rectangle of frame 2 Use crop instead of resample -- this seems best since it's just 1 pixel. I coded up #3 for you -- it works well static private void GenerateGifImage(FileStream fileStream, int OutputWidth, int OutputHeight) { // MemoryStream InputStream = new MemoryStream(); FileStream InputStream = fileStream; // fileStream.Write(InputStream.GetBuffer(), 0, (int)InputStream.Position); // InputStream.Seek(0, SeekOrigin.Begin); Image InputImage = Image.FromStream(InputStream, true, false); // this will invalidate the underlying image object in InputImage but the class properties // will still accessible until the object is disposed InputStream.Seek(0, SeekOrigin.Begin); ImageInfo imageInfo = RegisteredDecoders.GetImageInfo(InputStream); InputStream.Seek(0, SeekOrigin.Begin); GifDecoder gifDecoder = new GifDecoder(); int count = gifDecoder.GetFrameCount(InputStream); GifFrameCollection gifFrameCollection = new GifFrameCollection(); gifFrameCollection.Height = OutputHeight; gifFrameCollection.Width = OutputWidth; double ratio; if (InputImage.Height > InputImage.Width) { ratio = (double)OutputHeight / (double)InputImage.Height; } else { ratio = (double)OutputWidth / (double)InputImage.Width; } for (int i = 0; i < count; i++) { GifFrame frame = gifDecoder.Frames[i]; Rectangle rectangle = new Rectangle(Point.Empty, frame.Image.Size); int newframeWidth = frame.Image.Width; int newframeHeight = frame.Image.Height; if (newframeWidth > OutputWidth || newframeHeight > OutputHeight) { newframeWidth = (int)(frame.Image.Width * ratio); newframeHeight = (int)(frame.Image.Height * ratio); } // account for erratic rounding, seems illogical but has happened earlier when using floats instead of doubles if (newframeWidth > OutputWidth) { newframeWidth = OutputWidth; } if (newframeHeight > OutputHeight) { newframeHeight = OutputHeight; } Size size = new Size(newframeWidth, newframeHeight); // only resize if we have a measureable dimension if (size.Width > 0 && size.Height > 0) { //ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.); AtalaImage atalaImage = frame.Image; if (newframeWidth != frame.Image.Width || newframeHeight != frame.Image.Height) { CropCommand command = new CropCommand(new Rectangle(new Point(0, 0), size)); atalaImage = command.Apply(frame.Image).Image; } // AtalaImage atalaImage = frame.Image; Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); // Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); gifFrameCollection.Add(new GifFrame(atalaImage, point, frame.DelayTime, frame.Interlaced, frame.FrameDisposal, frame.TransparentIndex, frame.UseLocalPalette)); } } FileStream saveStream = new FileStream("resized.gif", FileMode.Create, FileAccess.Write, FileShare.Write); GifEncoder gifSave = new GifEncoder(); gifSave.Save(saveStream, gifFrameCollection, null); saveStream.Close(); }

Related questions

0 votes
    I am using Laravel Image Intervention to resize an image upload field on my form. This is the error ... Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Apr 17, 2022 in Education by JackTerrance
0 votes
    I want to display among other things a Label containing an Image , the image in this Label is a ... JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Feb 13, 2022 in Education by JackTerrance
0 votes
    Clip Organizer is used to store animated clips. true or false Select the correct answer from above options...
asked Dec 2, 2021 in Education by JackTerrance
0 votes
    C Write T for True and F for False 2. 1. The full form of GIF is Graphics Interchange Format. You can ... the current HTML document. Select the correct answer from above options...
asked Dec 27, 2021 in Education by JackTerrance
0 votes
    C Write T for True and F for False 2. 1. The full form of GIF is Graphics Interchange Format. You can ... the current HTML document. Select the correct answer from above options...
asked Dec 26, 2021 in Education by JackTerrance
0 votes
    which of these is not an image file format PNG GIF BMP DOCX Select the correct answer from above options...
asked Dec 19, 2021 in Education by JackTerrance
...