2013-07-27 9 views
7

मैं दो अलग-अलग gif फ़ाइल को एक फ़ाइल में गठबंधन करने की कोशिश कर रहा हूं।सी # में, शायद यह छवि के लिए एक बग है .aveAdd, जो इसे हल करने में मेरी मदद कर सकता है?

सबसे पहले, मैंने gif प्रारूप के बारे में बहुत कुछ सीखा। और मुझे पता है कि देरी समय मान ग्राफिक्स कंट्रोल एक्सटेंशन में सेट है जो gif फ़ाइल का एक ब्लॉक है।

मैं पहली बार gif बचाया और FrameDelay मूल्य, के रूप में नीचे दिए गए कोड को सेट करें:

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); 

तो मैं दूसरे फ्रेम के रूप में एक और छवि को जोड़ने की कोशिश की।

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); 

अंतिम, मुझे इस छवि को समाप्त करना चाहिए।

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

और मैंने पाया कि दूसरे फ्रेम की देरी समय हमेशा 0.

है मैं विधि का एक बहुत कोशिश की, लेकिन मैं पता नहीं 0x96 के रूप में यह सुनिश्चित करने के लिए है।

तो इसमें क्या गलत है?

+2

यह जीडीआई + में निर्मित जीआईएफ एन्कोडर द्वारा समर्थित नहीं है। आप यह काम नहीं कर सकते। –

+0

वास्तव में? क्या यह सच है?? –

+0

ठीक है, बेवकूफ सवाल, लेकिन बस यह सुनिश्चित करने के लिए: आप एनिमेटेड जीआईएफ के बारे में बात कर रहे हैं, है ना? – RenniePet

उत्तर

15

यह केवल नेट छवि एनकोडर के किसी भी द्वारा समर्थित नहीं है। जीडीआई + न ही डब्ल्यूआईसी द्वारा, System.Drawing.Bitmap और System.Windows.Media.Imaging.PngBitmapEncoder कक्षाओं के लिए अंतर्निहित मूल कोडेक्स।

हालांकि यह एक बहुत ही अजीब निरीक्षण की तरह लगता है, सबसे संभवतः यह था कि जीआईएफ को सॉफ्टवेयर पेटेंट द्वारा घेर लिया गया था। यूनिसिस के पास एलजेडब्लूडब्ल्यू संपीड़न एल्गोरिदम के अधिकार थे और aggressively pursuing इसके लिए लाइसेंस शुल्क प्राप्त करना शुरू किया। सबसे स्पष्ट लक्ष्यों से शुरू करना जहां अधिकतर धनराशि हो सकती है, माइक्रोसॉफ्ट हमेशा सूची के शीर्ष पर है। वे मामूली नहीं थे, एक गैर-वाणिज्यिक या निजी वेबसाइट जिसने अपने वेब पृष्ठों पर जीआईएफ का इस्तेमाल किया था, 1 999 में पांच हजार डॉलर खांसी खाई थी।

इसने छवि प्रारूप को मार दिया। इससे पहले सर्वव्यापी, बस हर किसी ने उनका उपयोग बंद कर दिया। आश्चर्यजनक रूप से भी जल्दी, यह केवल कुछ महीने लिया। खुशी से सभी को एनिमेटेड gifs btw भरने के साथ मिलकर, यह पहले से काफी अधिक था। आपको बैक-बैक मशीन पर कुछ वेब पेज मिल सकते हैं, जहां आंख के कोने में सबकुछ बढ़ रहा था। एकमात्र भाग्यशाली संयोग नहीं, ओपन सोर्स पीएनजी प्रारूप विकसित होने का मुख्य कारण था। हमारे भाग्यशाली सितारों का शुक्रिया :)

पेटेंट की अवधि 2004 के आसपास समाप्त हो गई, आप कहां रहते हैं, इस पर निर्भर करते हुए, आपको अब यूनिसिस से एक पत्र से डरना नहीं होगा।

लंबी कहानी छोटी, आपको इस कार्यक्रम को अपने कार्यक्रम में जोड़ने के लिए दूसरी लाइब्रेरी के लिए खरीदारी करना होगा। यह existing SO question द्वारा अच्छी तरह से कवर किया गया है, इसे यहां दोहराने की आवश्यकता नहीं है।

+3

+1 हंस के एक दिलचस्प और अंतर्दृष्टिपूर्ण उत्तर क्या है। साझा करने के लिए धन्यवाद! –

1

Microsoft Developer Center से: आप एनिमेटेड gif फ़ाइल में फ़्रेम जोड़ने के लिए SaveAdd का उपयोग नहीं कर सकते हैं।

एनिमेटेड gif बनाने के लिए, आपको एनीमेशन में प्रत्येक फ्रेम के माध्यम से कदम उठाने की आवश्यकता होगी। इसका एक अच्छा उदाहरण VCSKicks या same code here on Stackoverflow पर दिखाया गया है।

1

अद्यतन:

मैं और अधिक शोध किया और मुझे लगता है कि इन ffmpeg और MPlayer सिफारिशों कोशिश कर रहा लायक हैं:
Create animated gif from a set of jpeg images

अद्यतन 2:

Rick van den Bosch से इस कोड को बहुत है अच्छा भी है, क्योंकि यह आपको देरी के समय तक पहुंच प्रदान करता है:

नेट (कम से कम 1.1, वे इसे 2.0 में शामिल कर सकते हैं) आपको जीडीआई + के माध्यम से एनिमेटेड जीआईएफ बनाने की संभावना नहीं देता है।

//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(); 

के रूप में हंस उल्लेख अपने समर्थित नहीं है, तो यह तीसरे समाधान दोनों Gif से तख्ते निकालने और फिर सभी फ्रेम एक साथ गठबंधन करने के लिए RenniePet के सुझाव है।

सिस्टम के लिए एक संदर्भ जोड़ें। ड्रॉइंग।DLL और इस कोड का उपयोग फ्रेम पाने के लिए:

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 
    } 
} 

हम इस तरह सभी फ्रेम्स निकाल सकते हैं: का उपयोग कर

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; 
} 

अगला हम एक भी ऐनिमेटेड gif में सभी तख्तों गठबंधन NGif

कोड डाउनलोड करें, समाधान खोलें और DLL Gif.Components.dll प्राप्त करने के लिए घटक प्रोजेक्ट संकलित करें और संदर्भ दें कि आपके समाधान में DLL।

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

यदि आप किसी तृतीय पक्ष लाइब्रेरी का उपयोग करने के इच्छुक हैं तो आप Magick.NET का उपयोग कर सकते हैं। यह 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"); 
} 
संबंधित मुद्दे

 संबंधित मुद्दे