2013-07-27 4 views
7

Ich versuche, zwei verschiedene gif-Datei in einer Datei zu kombinieren.In C#, vielleicht ist es ein Fehler für Image.SaveAdd, wer kann mir helfen, es zu lösen?

Zuerst habe ich viel über das gif-Format gelernt. Und ich weiß, dass der Wert der Verzögerungszeit in Graphics Control Extension eingestellt ist, welches ein Block der gif-Datei ist.

gespeichert ich die erste gif und stellen Sie den FrameDelay Wert, Code, wie unten:

ImageCodecInfo codeInfo = GetEncoder(ImageFormat.Gif); 
    System.Drawing.Imaging.Encoder saveEncoder = System.Drawing.Imaging.Encoder.SaveFlag; 
    EncoderParameters parameters = new EncoderParameters(1); 

    parameters.Param[0] = new EncoderParameter(saveEncoder, (long)EncoderValue.MultiFrame); 
    PropertyItem PropertyTagFrameDelay = img1.GetPropertyItem(0x5100); 
    PropertyTagFrameDelay.Value = new byte[] { 0x96, 0x00 };// this is the delay value 0x0096, means 1.5 second 
    img1.SetPropertyItem(PropertyTagFrameDelay); 

    PropertyItem LoopCount = img1.GetPropertyItem(0x5101); 
    LoopCount.Value = new byte[] { 0x00, 0x00 };// this means the gif loops endlessly 
    img1.SetPropertyItem(LoopCount); 

    img1.Save(@"c:\ddd.gif", codeInfo, parameters); 

Dann habe ich versucht, ein anderes Bild als zweiten Rahmen hinzuzufügen.

parameters = new EncoderParameters(1); 
    parameters.Param[0] = new EncoderParameter(saveEncoder, (long)EncoderValue.FrameDimensionTime); 
    PropertyTagFrameDelay = img2.GetPropertyItem(0x5100); 
    PropertyTagFrameDelay.Value = new byte[] { 0x96, 0x00 };// this is the delay value 0x0096, means 1.5 second 
    img2.SetPropertyItem(PropertyTagFrameDelay); 

Zuletzt sollte ich dieses Bild beenden.

parameters = new EncoderParameters(1); 
    parameters.Param[0] = new EncoderParameter(saveEncoder, (long)EncoderValue.Flush); 
    img1.SaveAdd(parameters); 

Und ich fand, dass die Verzögerungszeit des zweiten Rahmens ist immer 0.

habe ich versucht, eine Menge Methode, aber ich habe keine Ahnung, dass es als 0x96 zu machen.

Also was ist los damit?

+2

Es wird einfach nicht von dem in GDI + eingebauten GIF-Encoder unterstützt. Das kann nicht funktionieren. –

+0

wirklich? Ist es wahr?? –

+0

OK, blöde Frage, aber nur um sicher zu sein: Du redest über animierte GIFs, oder? – RenniePet

Antwort

15

Dieses einfach nicht von unterstützt jede der .NET-Bildgebern. Weder von GDI + noch von WIC, die zugrunde liegenden nativen Codecs für die Klassen System.Drawing.Bitmap und System.Windows.Media.Imaging.PngBitmapEncoder.

Während das klingt wie eine sehr seltsame Aufsicht, der wahrscheinlichste Grund war, dass GIF durch ein Softwarepatent belastet war. Unisys besaß die Rechte an dem LZW-Komprimierungsalgorithmus und startete aggressively pursuing, um die Lizenzgebühren dafür zu erhalten. Beginnend bei den offensichtlichsten Zielen, wo das meiste Geld zu haben ist, steht Microsoft für immer an der Spitze der Liste. Sie waren entweder nicht bescheiden, eine nicht-kommerzielle oder private Website, die GIFs auf ihren Web-Seiten mußten husten fünftausend Dollar im Jahr 1999.

Dieser tötete das Bildformat. Vorher allgegenwärtig, haben fast alle aufgehört, sie zu benutzen. Atemberaubend schnell auch, dies dauerte nur ein paar Monate. Glücklich zusammen mit allen, die ihre Fülle an animierten Gifs btw voll hatten, war es schon sehr übertrieben. Sie können einige Webseiten von damals auf dem Weg zurück Maschine finden, wo alles in der Ecke des Auges bewegte. Nicht der einzige glückliche Zufall, es war der Hauptgrund für die Entwicklung des Open-Source-PNG-Formats. Danke unseren Glücksstern :)

Das Patent lief um 2004 ab, je nachdem, wo du lebst, so dass du keinen Brief von Unisys mehr fürchten musst.

Lange Rede kurzer Sinn, Sie müssen für eine andere Bibliothek einkaufen, um diese Funktion zu Ihrem Programm hinzuzufügen. Es ist gut abgedeckt durch diese existing SO question, keine Notwendigkeit, es hier zu wiederholen.

+3

+1 Was für eine interessante und aufschlussreiche Antwort Hans. Danke für das Teilen! –

1

Update:

habe ich mehr Forschung und ich denke, diese ffmpeg und MPlayer Empfehlungen wert sind, die versuchen:
Create animated gif from a set of jpeg images

Update 2:

Dieser Code von Rick van den Bosch ist sehr auch gut, da Sie auf die Verzögerungszeiten zugreifen können:

.Net (mindestens 1.1, sie könnten es in 2.0 enthalten) gibt Sie Möglichkeiten, animierte GIFs über GDI + zu erstellen.

//Variable declaration 
StringCollection stringCollection; 
MemoryStream memoryStream; 
BinaryWriter binaryWriter; 
Image image; 
Byte[] buf1; 
Byte[] buf2; 
Byte[] buf3; 
//Variable declaration 

stringCollection = a_StringCollection_containing_images; 

Response.ContentType = "Image/gif"; 
memoryStream = new MemoryStream(); 
buf2 = new Byte[19]; 
buf3 = new Byte[8]; 
buf2[0] = 33; //extension introducer 
buf2[1] = 255; //application extension 
buf2[2] = 11; //size of block 
buf2[3] = 78; //N 
buf2[4] = 69; //E 
buf2[5] = 84; //T 
buf2[6] = 83; //S 
buf2[7] = 67; //C 
buf2[8] = 65; //A 
buf2[9] = 80; //P 
buf2[10] = 69; //E 
buf2[11] = 50; //2 
buf2[12] = 46; //. 
buf2[13] = 48; //0 
buf2[14] = 3; //Size of block 
buf2[15] = 1; // 
buf2[16] = 0; // 
buf2[17] = 0; // 
buf2[18] = 0; //Block terminator 
buf3[0] = 33; //Extension introducer 
buf3[1] = 249; //Graphic control extension 
buf3[2] = 4; //Size of block 
buf3[3] = 9; //Flags: reserved, disposal method, user input, transparent color 
buf3[4] = 10; //Delay time low byte 
buf3[5] = 3; //Delay time high byte 
buf3[6] = 255; //Transparent color index 
buf3[7] = 0; //Block terminator 
binaryWriter = new BinaryWriter(Response.OutputStream); 
for (int picCount = 0; picCount < stringCollection.Count; picCount++) 
{ 
    image = Bitmap.FromFile(stringCollection[picCount]); 
    image.Save(memoryStream, ImageFormat.Gif); 
    buf1 = memoryStream.ToArray(); 

    if (picCount == 0) 
    { 
     //only write these the first time.... 
     binaryWriter.Write(buf1, 0, 781); //Header & global color table 
     binaryWriter.Write(buf2, 0, 19); //Application extension 
    } 

    binaryWriter.Write(buf3, 0, 8); //Graphic extension 
    binaryWriter.Write(buf1, 789, buf1.Length - 790); //Image data 

    if (picCount == stringCollection.Count - 1) 
    { 
     //only write this one the last time.... 
     binaryWriter.Write(";"); //Image terminator 
    } 

    memoryStream.SetLength(0); 
} 
binaryWriter.Close(); 
Response.End(); 

Wie Hans erwähnte seine nicht unterstützt, so dass diese dritte Lösung ist Vorschlag des RenniePet den Rahmen von sowohl GIF zu extrahieren und dann gemeinsam all Frames zu kombinieren.

Fügen Sie einen Verweis auf System.Drawing hinzu.DLL und diesen Code verwenden, um die Bilder zu bekommen:

using System.Drawing; 
using System.Drawing.Imaging; 

public class GifImage 
{ 
    private Image gifImage; 
    private FrameDimension dimension; 
    private int frameCount; 
    private int currentFrame = -1; 
    private bool reverse; 
    private int step = 1; 

    public GifImage(string path) 
    { 
     gifImage = Image.FromFile(path); 
     //initialize 
     dimension = new FrameDimension(gifImage.FrameDimensionsList[0]); 
     //gets the GUID 
     //total frames in the animation 
     frameCount = gifImage.GetFrameCount(dimension); 
    } 

    public int GetFrameCount() 
    { 
     return frameCount; 
    } 

    public bool ReverseAtEnd 
    { 
     //whether the gif should play backwards when it reaches the end 
     get { return reverse; } 
     set { reverse = value; } 
    } 

    public Image GetNextFrame() 
    { 

     currentFrame += step; 

     //if the animation reaches a boundary... 
     if (currentFrame >= frameCount || currentFrame < 1) 
     { 
      if (reverse) 
      { 
       step *= -1; 
       //...reverse the count 
       //apply it 
       currentFrame += step; 
      } 
      else 
      { 
       currentFrame = 0; 
       //...or start over 
      } 
     } 
     return GetFrame(currentFrame); 
    } 

    public Image GetFrame(int index) 
    { 
     gifImage.SelectActiveFrame(dimension, index); 
     //find the frame 
     return (Image)gifImage.Clone(); 
     //return a copy of it 
    } 
} 

Wir alle Frames wie folgt extrahieren:

private static readonly string tempFolder = @"C:\temp\"; 

static void Main(string[] args) 
{ 
    CombineGifs(@"c:\temp\a.gif", @"c:\temp\b.gif"); 
} 

public static void CombineGifs(string firstImageFilePath, string secondImageFilePath) 
{ 
    int frameCounter = ExtractGifFramesAndGetCount(firstImageFilePath, 0); 
    int secondframeCounter = ExtractGifFramesAndGetCount(secondImageFilePath, frameCounter); 

    string filePathOfCombinedGif = CombineFramesIntoGif(0, secondframeCounter); 
} 

private static int ExtractGifFramesAndGetCount(string filePath, int imageNameStartNumber) 
{ 
    ////NGif had an error when I tried it 
    //GifDecoder gifDecoder = new GifDecoder(); 
    //gifDecoder.Read(filePath); 

    //int frameCounter = imageNameStartNumber + gifDecoder.GetFrameCount(); 
    //for (int i = imageNameStartNumber; i < frameCounter; i++) 
    //{ 
    // Image frame = gifDecoder.GetFrame(i); // frame i 
    // frame.Save(tempFolder + i.ToString() + ".png", ImageFormat.Png); 
    //} 

    //So we'll use the Gifimage implementation 
    GifImage gifImage = new GifImage(filePath); 
    gifImage.ReverseAtEnd = false; 
    int frameCounter = imageNameStartNumber + gifImage.GetFrameCount(); 
    for (int i = imageNameStartNumber; i < frameCounter; i++) 
    { 
     Image img = gifImage.GetNextFrame(); 
     img.Save(tempFolder + i.ToString() + ".png"); 
    } 
    return frameCounter; 
} 

Als nächstes werden wir alle Bilder in eine animierte gif mit NGif

kombinieren Laden Sie den Code herunter, öffnen Sie die Lösung und kompilieren Sie das Komponenten-Projekt, um die DLL Gif.Components.dll zu erhalten, und verweisen Sie auf diese DLL in Ihrer Lösung.

private static string CombineFramesIntoGif(int startFrameCount, int endFrameCount) 
{ 
    List<string> imageFilePaths = new List<string>(); 
    for (int i = startFrameCount; i < endFrameCount; i++) 
    { 
     imageFilePaths.Add(tempFolder + i.ToString() + ".png"); 
    } 

    string outputFilePath = tempFolder + "test.gif"; 
    AnimatedGifEncoder e = new AnimatedGifEncoder(); 
    e.Start(outputFilePath); 
    e.SetDelay(500); 
    //-1:no repeat,0:always repeat 
    e.SetRepeat(0); 
    for (int i = 0; i < imageFilePaths.Count; i++) 
    { 
     e.AddFrame(Image.FromFile(imageFilePaths[i])); 
    } 
    e.Finish(); 
    return outputFilePath; 
} 
1

Wenn Sie eine Drittanbieter-Bibliothek verwenden möchten, können Sie Magick.NET verwenden. Dies ist ein C# -Wrapper für ImageMagick.

using (MagickImageCollection images = new MagickImageCollection()) 
{ 
    MagickImage firstFrame = new MagickImage("first.gif"); 
    firstFrame.AnimationDelay = 1500; 
    images.Add(firstFrame); 

    MagickImage secondFrame = new MagickImage("second.gif"); 
    secondFrame.AnimationDelay = 200; 
    images.Add(secondFrame); 

    // This method will try to make your output image smaller. 
    images.OptimizePlus(); 

    images.Write(@"c:\ddd.gif"); 
} 
Verwandte Themen