誰でもC#を使ってアニメーションGIFを作成する方法を知っていますか? 理想的には、使用されている色の減色を何らかの形で制御します。.netでアニメーションgifを作成する方法
imagemagick(外部開始プロセスとして)を使用するのが最適ですか?
誰でもC#を使ってアニメーションGIFを作成する方法を知っていますか? 理想的には、使用されている色の減色を何らかの形で制御します。.netでアニメーションgifを作成する方法
imagemagick(外部開始プロセスとして)を使用するのが最適ですか?
imagemagickを呼び出すことが最善の選択であるかどうかは、重要な品質パラメータを知らなくても、一見難しいことです。いくつかの他のオプションは次のようになります。これらはあなたがかもしれないまたはかもしれない第三、一部のライブラリに依存していないという利点がある
をCodePlexの上
MSサポートのarticleでは、カスタムカラーテーブルを使用してgifを保存する方法について説明しています(完全信頼が必要です)。アニメーションGIFは、ヘッダーにいくつかの追加情報を加えた各画像の単なるGIFのセットです。したがって、これら2つの記事を組み合わせることで、必要なものを得ることができます。
GIFファイルをエンコードする.NETクラスが組み込まれています。
します。C:\ Program Files \リファレンスアセンブリ\マイクロソフト\ Framework.NETFramework \ v4.0の\ PresentationCore Windowsからのサンプルを使用するには GifBitmapEncode MSDN
System.Windows.Media.Imaging.GifBitmapEncoder gEnc = new GifBitmapEncoder();
foreach (System.Drawing.Bitmap bmpImage in images)
{
var bmp = bmpImage.GetHbitmap();
var src = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmp,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
gEnc.Frames.Add(BitmapFrame.Create(src));
DeleteObject(bmp); // recommended, handle memory leak
}
using(FileStream fs = new FileStream(path, FileMode.Create))
{
gEnc.Save(fs);
}
このコードを使用して各フレーム間に一定の遅延を持たせる方法や、フレームレートを設定する方法はありますか? – uSeRnAmEhAhAhAhAhA
Um。このコードは大量に失敗します。それは、画像の束を互いに重ね合わせて一つの画像として保存することだけです。 – uSeRnAmEhAhAhAhAhA
上記のソリューションでは、GDI Bitmapオブジェクトによって引き起こされる可能性のあるメモリリークを処理する必要があります。これは、指定されたコードの 'bmpImage.GetHbitmap()'です。 [MSDNのメモとして、これは手動で削除する必要があります](https://msdn.microsoft.com/en-us/library/1dz311e4.aspx)。 [Here](https://msdn.microsoft.com/en-us/library/1dz311e4.aspx#Anchor_3)は、GDI Bitmapオブジェクトがあまりにも多くのメモリを占有しないようにするためのコード例です。 – vburca
は、これらのアセンブリへの参照を追加し、アプリをフォーム.dll C:¥Program Files¥Reference Assemblies¥Microsoft¥Framework.NETFramework¥v4.0¥System.Xaml.dll C:¥Program Files¥Referenceアセンブリ言語¥Microsoft¥Framework.NETFramework¥v4.0¥WindowsBase.dll
次に
Int32Rectは
BitmapSizeOptionsが
BitmapFrameがSystem.Windows.Media.Imaging名前空間
にあるSystem.Windows.Media.Imaging名前空間にあるSystem.Windows名前空間でありますまた、ファイルストリームをクローズすることを忘れないでください(このようなもの):
using(FileStream targetFile = new FileStream(path, FileMode.Create))
{
gEnc.Save(targetFile);
}
また、ImageMagickライブラリの使用を検討することもできます。
2つあります。ここでhttp://www.imagemagick.org/script/api.php
に掲載されているライブラリの純ラッパーはMagick.net wrapperを使用してそれを行う方法についての例です。
using (MagickImageCollection collection = new MagickImageCollection())
{
// Add first image and set the animation delay to 100ms
collection.Add("Snakeware.png");
collection[0].AnimationDelay = 100;
// Add second image, set the animation delay to 100ms and flip the image
collection.Add("Snakeware.png");
collection[1].AnimationDelay = 100;
collection[1].Flip();
// Optionally reduce colors
QuantizeSettings settings = new QuantizeSettings();
settings.Colors = 256;
collection.Quantize(settings);
// Optionally optimize the images (images should have the same size).
collection.Optimize();
// Save gif
collection.Write("Snakeware.Animated.gif");
}
https://github.com/DataDink/BumpkitからこれのGIFアニメーションクリエーターコードが遅延foreachのフレームを設定することができます。
使用方法を.Net標準GIFエンコーディングとアニメーションヘッダーを追加します。
EDIT:一般的なファイルライターに似たコードを作成しました。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
/// <summary>
/// Creates a GIF using .Net GIF encoding and additional animation headers.
/// </summary>
public class GifWriter : IDisposable
{
#region Fields
const long SourceGlobalColorInfoPosition = 10,
SourceImageBlockPosition = 789;
readonly BinaryWriter _writer;
bool _firstFrame = true;
readonly object _syncLock = new object();
#endregion
/// <summary>
/// Creates a new instance of GifWriter.
/// </summary>
/// <param name="OutStream">The <see cref="Stream"/> to output the Gif to.</param>
/// <param name="DefaultFrameDelay">Default Delay between consecutive frames... FrameRate = 1000/DefaultFrameDelay.</param>
/// <param name="Repeat">No of times the Gif should repeat... -1 to repeat indefinitely.</param>
public GifWriter(Stream OutStream, int DefaultFrameDelay = 500, int Repeat = -1)
{
if (OutStream == null)
throw new ArgumentNullException(nameof(OutStream));
if (DefaultFrameDelay <= 0)
throw new ArgumentOutOfRangeException(nameof(DefaultFrameDelay));
if (Repeat < -1)
throw new ArgumentOutOfRangeException(nameof(Repeat));
_writer = new BinaryWriter(OutStream);
this.DefaultFrameDelay = DefaultFrameDelay;
this.Repeat = Repeat;
}
/// <summary>
/// Creates a new instance of GifWriter.
/// </summary>
/// <param name="FileName">The path to the file to output the Gif to.</param>
/// <param name="DefaultFrameDelay">Default Delay between consecutive frames... FrameRate = 1000/DefaultFrameDelay.</param>
/// <param name="Repeat">No of times the Gif should repeat... -1 to repeat indefinitely.</param>
public GifWriter(string FileName, int DefaultFrameDelay = 500, int Repeat = -1)
: this(new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read), DefaultFrameDelay, Repeat) { }
#region Properties
/// <summary>
/// Gets or Sets the Default Width of a Frame. Used when unspecified.
/// </summary>
public int DefaultWidth { get; set; }
/// <summary>
/// Gets or Sets the Default Height of a Frame. Used when unspecified.
/// </summary>
public int DefaultHeight { get; set; }
/// <summary>
/// Gets or Sets the Default Delay in Milliseconds.
/// </summary>
public int DefaultFrameDelay { get; set; }
/// <summary>
/// The Number of Times the Animation must repeat.
/// -1 indicates no repeat. 0 indicates repeat indefinitely
/// </summary>
public int Repeat { get; }
#endregion
/// <summary>
/// Adds a frame to this animation.
/// </summary>
/// <param name="Image">The image to add</param>
/// <param name="Delay">Delay in Milliseconds between this and last frame... 0 = <see cref="DefaultFrameDelay"/></param>
public void WriteFrame(Image Image, int Delay = 0)
{
lock (_syncLock)
using (var gifStream = new MemoryStream())
{
Image.Save(gifStream, ImageFormat.Gif);
// Steal the global color table info
if (_firstFrame)
InitHeader(gifStream, _writer, Image.Width, Image.Height);
WriteGraphicControlBlock(gifStream, _writer, Delay == 0 ? DefaultFrameDelay : Delay);
WriteImageBlock(gifStream, _writer, !_firstFrame, 0, 0, Image.Width, Image.Height);
}
if (_firstFrame)
_firstFrame = false;
}
#region Write
void InitHeader(Stream SourceGif, BinaryWriter Writer, int Width, int Height)
{
// File Header
Writer.Write("GIF".ToCharArray()); // File type
Writer.Write("89a".ToCharArray()); // File Version
Writer.Write((short)(DefaultWidth == 0 ? Width : DefaultWidth)); // Initial Logical Width
Writer.Write((short)(DefaultHeight == 0 ? Height : DefaultHeight)); // Initial Logical Height
SourceGif.Position = SourceGlobalColorInfoPosition;
Writer.Write((byte)SourceGif.ReadByte()); // Global Color Table Info
Writer.Write((byte)0); // Background Color Index
Writer.Write((byte)0); // Pixel aspect ratio
WriteColorTable(SourceGif, Writer);
// App Extension Header for Repeating
if (Repeat == -1)
return;
Writer.Write(unchecked((short)0xff21)); // Application Extension Block Identifier
Writer.Write((byte)0x0b); // Application Block Size
Writer.Write("NETSCAPE2.0".ToCharArray()); // Application Identifier
Writer.Write((byte)3); // Application block length
Writer.Write((byte)1);
Writer.Write((short)Repeat); // Repeat count for images.
Writer.Write((byte)0); // terminator
}
static void WriteColorTable(Stream SourceGif, BinaryWriter Writer)
{
SourceGif.Position = 13; // Locating the image color table
var colorTable = new byte[768];
SourceGif.Read(colorTable, 0, colorTable.Length);
Writer.Write(colorTable, 0, colorTable.Length);
}
static void WriteGraphicControlBlock(Stream SourceGif, BinaryWriter Writer, int FrameDelay)
{
SourceGif.Position = 781; // Locating the source GCE
var blockhead = new byte[8];
SourceGif.Read(blockhead, 0, blockhead.Length); // Reading source GCE
Writer.Write(unchecked((short)0xf921)); // Identifier
Writer.Write((byte)0x04); // Block Size
Writer.Write((byte)(blockhead[3] & 0xf7 | 0x08)); // Setting disposal flag
Writer.Write((short)(FrameDelay/10)); // Setting frame delay
Writer.Write(blockhead[6]); // Transparent color index
Writer.Write((byte)0); // Terminator
}
static void WriteImageBlock(Stream SourceGif, BinaryWriter Writer, bool IncludeColorTable, int X, int Y, int Width, int Height)
{
SourceGif.Position = SourceImageBlockPosition; // Locating the image block
var header = new byte[11];
SourceGif.Read(header, 0, header.Length);
Writer.Write(header[0]); // Separator
Writer.Write((short)X); // Position X
Writer.Write((short)Y); // Position Y
Writer.Write((short)Width); // Width
Writer.Write((short)Height); // Height
if (IncludeColorTable) // If first frame, use global color table - else use local
{
SourceGif.Position = SourceGlobalColorInfoPosition;
Writer.Write((byte)(SourceGif.ReadByte() & 0x3f | 0x80)); // Enabling local color table
WriteColorTable(SourceGif, Writer);
}
else Writer.Write((byte)(header[9] & 0x07 | 0x07)); // Disabling local color table
Writer.Write(header[10]); // LZW Min Code Size
// Read/Write image data
SourceGif.Position = SourceImageBlockPosition + header.Length;
var dataLength = SourceGif.ReadByte();
while (dataLength > 0)
{
var imgData = new byte[dataLength];
SourceGif.Read(imgData, 0, dataLength);
Writer.Write((byte)dataLength);
Writer.Write(imgData, 0, dataLength);
dataLength = SourceGif.ReadByte();
}
Writer.Write((byte)0); // Terminator
}
#endregion
/// <summary>
/// Frees all resources used by this object.
/// </summary>
public void Dispose()
{
// Complete File
_writer.Write((byte)0x3b); // File Trailer
_writer.BaseStream.Dispose();
_writer.Dispose();
}
}
私は、ImageMagicとNGifのもう1つの偉大な選択肢はまだ答えに載っていないことに気付きました。
FFMpegは、アニメーションGIFを作成するために使用することができるから:
としてあなたは(System.Diagnostics.Process付き)C#コードからffmpeg.exe直接起動したり、existinのいずれかを使用することができますグラム.NETのffmpegのラッパー:
var ffmpeg = new NReco.VideoConverter.FFMpegConverter();
ffmpeg.ConvertMedia("your_clip.mp4", null, "result.gif", null, new ConvertSettings());
(このコード例では、フリーNReco VideoConverterを使用しています - 私は、その使用に関するご質問をお気軽に、このコンポーネントの作者です)。
GIFサイズは、フレームレートおよび/またはフレームサイズを減らすことによって簡単に減らすことができます。 また、最適なGIFパレットを生成する2パスアプローチで、細かいアニメーションGIFを取得することも可能です。
imagemagickにはまだ最適なオプション(ディザリング、カラーリダクションなど)があるようです。提案されたlibやその他の作成方法はかなり劣っています –
あなたは最終的な解決策を試しましたか?答えが表示されていません... – Kiquenet