fixed #324: GIF header changes to fix Twitter problem, saving directly to hard disk instead memory

This commit is contained in:
Jaex 2014-10-08 22:03:08 +03:00
parent 979259000f
commit d7ae4c4571
4 changed files with 51 additions and 45 deletions

View file

@ -131,5 +131,10 @@ public static T Read<T>(this Stream stream)
return retval;
}
public static void Write(this FileStream stream, byte[] array)
{
stream.Write(array, 0, array.Length);
}
}
}

View file

@ -29,21 +29,20 @@ You should have received a copy of the GNU General Public License
namespace HelpersLib
{
public class GifCreator : IDisposable
public class AnimatedGifCreator : IDisposable
{
private byte[] graphicControlExtensionBlock, loopBlock;
private MemoryStream gifStream;
private BinaryWriter binaryWriter;
private int frameNum;
public string FilePath { get; private set; }
public int Delay { get; private set; }
public int Repeat { get; private set; }
public int FrameCount { get; private set; }
public GifCreator(int delay, int repeat = 0)
private FileStream stream;
public AnimatedGifCreator(string filePath, int delay, int repeat = 0)
{
byte[] signature = new byte[] { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' };
graphicControlExtensionBlock = CreateGraphicControlExtensionBlock(delay);
loopBlock = CreateLoopBlock(repeat);
gifStream = new MemoryStream();
binaryWriter = new BinaryWriter(gifStream);
binaryWriter.Write(signature);
FilePath = filePath;
Delay = delay;
Repeat = repeat;
}
public void AddFrame(Image img, GIFQuality quality = GIFQuality.Default)
@ -51,17 +50,20 @@ public void AddFrame(Image img, GIFQuality quality = GIFQuality.Default)
GifClass gif = new GifClass();
gif.LoadGifPicture(img, quality);
if (frameNum == 0)
if (stream == null)
{
binaryWriter.Write(gif.m_ScreenDescriptor.ToArray());
stream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.Read);
stream.Write(CreateHeaderBlock());
stream.Write(gif.m_ScreenDescriptor.ToArray());
stream.Write(CreateApplicationExtensionBlock(Repeat));
}
binaryWriter.Write(graphicControlExtensionBlock);
binaryWriter.Write(gif.m_ImageDescriptor.ToArray());
binaryWriter.Write(gif.m_ColorTable.ToArray());
binaryWriter.Write(gif.m_ImageData.ToArray());
stream.Write(CreateGraphicsControlExtensionBlock(Delay));
stream.Write(gif.m_ImageDescriptor.ToArray());
stream.Write(gif.m_ColorTable.ToArray());
stream.Write(gif.m_ImageData.ToArray());
frameNum++;
FrameCount++;
}
public void AddFrame(string path, GIFQuality quality = GIFQuality.Default)
@ -72,38 +74,32 @@ public void AddFrame(string path, GIFQuality quality = GIFQuality.Default)
}
}
public void Finish()
private void Finish()
{
binaryWriter.Write(CreateLoopBlock());
binaryWriter.Write(0x3B); // Image terminator
if (stream != null)
{
stream.WriteByte(0x3B); // Image terminator
stream.Dispose();
}
}
public void Save(string filePath)
public void Dispose()
{
gifStream.WriteToFile(filePath);
Finish();
}
private byte[] CreateGraphicControlExtensionBlock(int delay)
private byte[] CreateHeaderBlock()
{
byte[] buffer = new byte[8];
buffer[0] = 0x21; // Extension introducer
buffer[1] = 0xF9; // Graphic control extension
buffer[2] = 0x04; // Size of block
buffer[3] = 0x09; // Flags: reserved, disposal method, user input, transparent color
buffer[4] = (byte)(delay / 10 % 0x100); // Delay time low byte
buffer[5] = (byte)(delay / 10 / 0x100); // Delay time high byte
buffer[6] = 0xFF; // Transparent color index
buffer[7] = 0x00; // Block terminator
return buffer;
return new byte[] { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' };
}
private byte[] CreateLoopBlock(int repeat = 0)
private byte[] CreateApplicationExtensionBlock(int repeat)
{
byte[] buffer = new byte[19];
buffer[0] = 0x21; // Extension introducer
buffer[1] = 0xFF; // Application extension
buffer[2] = 0x0B; // Size of block
buffer[3] = (byte)'N';
buffer[3] = (byte)'N'; // NETSCAPE2.0
buffer[4] = (byte)'E';
buffer[5] = (byte)'T';
buffer[6] = (byte)'S';
@ -122,10 +118,18 @@ private byte[] CreateLoopBlock(int repeat = 0)
return buffer;
}
public void Dispose()
private byte[] CreateGraphicsControlExtensionBlock(int delay)
{
if (gifStream != null) gifStream.Dispose();
if (binaryWriter != null) binaryWriter.Close();
byte[] buffer = new byte[8];
buffer[0] = 0x21; // Extension introducer
buffer[1] = 0xF9; // Graphic control extension
buffer[2] = 0x04; // Size of block
buffer[3] = 0x09; // Flags: reserved, disposal method, user input, transparent color
buffer[4] = (byte)(delay / 10 % 0x100); // Delay time low byte
buffer[5] = (byte)(delay / 10 / 0x100); // Delay time high byte
buffer[6] = 0xFF; // Transparent color index
buffer[7] = 0x00; // Block terminator
return buffer;
}
}
}

View file

@ -240,7 +240,7 @@
<SubType>Form</SubType>
</Compile>
<Compile Include="GIF\GifClass.cs" />
<Compile Include="GIF\GifCreator.cs" />
<Compile Include="GIF\AnimatedGifCreator.cs" />
<Compile Include="GIF\GrayscaleQuantizer.cs" />
<Compile Include="GIF\OctreeQuantizer.cs" />
<Compile Include="GIF\PaletteQuantizer.cs" />

View file

@ -206,7 +206,7 @@ public void SaveAsGIF(string path, GIFQuality quality)
{
HardDiskCache hdCache = imgCache as HardDiskCache;
using (GifCreator gifEncoder = new GifCreator(delay))
using (AnimatedGifCreator gifEncoder = new AnimatedGifCreator(path, delay))
{
int i = 0;
int count = hdCache.Count;
@ -221,9 +221,6 @@ public void SaveAsGIF(string path, GIFQuality quality)
gifEncoder.AddFrame(img, quality);
}
}
gifEncoder.Finish();
gifEncoder.Save(path);
}
}
}