2013-07-27 42 views
7

Tôi đang cố gắng kết hợp hai tệp gif khác nhau vào một tệp.Trong C#, có thể đó là lỗi cho Image.SaveAdd, ai có thể giúp tôi giải quyết nó?

Trước tiên, tôi đã học được rất nhiều về định dạng gif. Và tôi biết giá trị thời gian trễ được đặt trong phần Mở rộng Điều khiển Đồ hoạ, là một khối tệp gif.

Tôi đã lưu gif đầu tiên và thiết lập giá trị FrameDelay, mã như sau:

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

Sau đó, tôi cố gắng thêm hình ảnh khác như khung thứ hai.

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

Cuối cùng, tôi nên chấm dứt hình ảnh này.

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

Và tôi thấy rằng thời gian trễ khung thứ hai luôn 0.

là tôi đã cố gắng rất nhiều phương pháp, nhưng tôi không có ý tưởng để làm cho nó như 0x96.

Vì vậy, có gì sai với nó?

+2

Nó chỉ đơn giản là không được hỗ trợ bởi bộ mã hóa gif được tích hợp vào GDI +. Bạn không thể thực hiện công việc này. –

+0

thực sự? Có đúng không ?? –

+0

OK, câu hỏi ngu ngốc, nhưng chỉ để chắc chắn: Bạn đang nói về GIF động, phải không? – RenniePet

Trả lời

15

này chỉ đơn giản là không được hỗ trợ bởi bất kỳ của các bộ mã hóa hình ảnh NET. Không phải bởi GDI + cũng như WIC, các codec gốc cơ bản cho các lớp học System.Drawing.BitmapSystem.Windows.Media.Imaging.PngBitmapEncoder.

Trong khi đó âm thanh như một sự giám sát rất lạ, lý do có lẽ nhất là GIF bị vướng bận bởi bằng sáng chế phần mềm. Unisys sở hữu các quyền đối với thuật toán nén LZW và bắt đầu aggressively pursuing thu phí giấy phép cho nó. Bắt đầu từ những mục tiêu rõ ràng nhất, nơi mà hầu hết tiền có thể có, Microsoft là mãi mãi trên đầu danh sách. Họ không phải là khiêm tốn, hoặc, một trang web phi thương mại hoặc cá nhân mà sử dụng GIF trên các trang web của họ đã phải ho lên năm ngàn USD vào năm 1999.

này giết chết các định dạng hình ảnh. Phổ biến trước đây, chỉ là về tất cả mọi người ngừng sử dụng chúng. Thật nhanh chóng, quá trình này chỉ mất một vài tháng. Hạnh phúc trùng hợp với tất cả mọi người hoàn toàn có đầy đủ của họ hoạt hình gif btw, nó đã được grossly overdone trước. Bạn có thể tìm thấy một số trang web từ sau đó trên máy quay lại nơi mọi thứ ở góc mắt đang di chuyển. Không phải ngẫu nhiên may mắn duy nhất, đó là lý do cốt lõi cho định dạng PNG nguồn mở đang được phát triển. Cảm ơn các ngôi sao may mắn của chúng tôi :)

Bằng sáng chế hết hạn vào khoảng năm 2004, tùy thuộc vào nơi bạn sinh sống, vì vậy bạn sẽ không phải sợ thư từ Unisys nữa.

Tóm tắt câu chuyện dài, bạn sẽ phải mua sắm quanh một thư viện khác để thêm tính năng này vào chương trình của bạn. Nó được che phủ bởi existing SO question, không cần lặp lại nó ở đây.

+3

+1 Câu trả lời thú vị và sâu sắc của Hans. Cám ơn vì đã chia sẻ! –

1

Cập nhật:

tôi đã nghiên cứu nhiều hơn và tôi nghĩ rằng những ffmpeg và khuyến nghị mplayer có giá trị cố gắng:
Create animated gif from a set of jpeg images

Cập nhật 2:

Mã này từ Rick van den Bosch là rất cũng tốt, vì nó cho phép bạn truy cập vào thời gian trễ:

.Net (ít nhất 1.1, chúng có thể kết hợp nó trong 2.0) không cung cấp cho khả năng tạo GIF động thông qua GDI +.

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

Như Hans nói nó không được hỗ trợ, vì vậy giải pháp thứ ba này là gợi ý RenniePet để trích xuất các khung hình từ cả hai Gif và sau đó kết hợp tất cả các khung hình lại với nhau.

Thêm tham chiếu vào System.Drawing.DLL và sử dụng mã này để có được những khung hình:

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

Chúng ta có thể trích xuất tất cả các khung hình như thế này:

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

Tiếp theo chúng ta kết hợp tất cả các khung hình thành một gif động đơn sử dụng NGif

Tải xuống mã, mở Solution và biên dịch dự án Components để lấy DLL Gif.Components.dll và tham khảo DLL đó trong giải pháp của bạn.

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

Nếu bạn sẵn sàng sử dụng thư viện của bên thứ ba, bạn có thể sử dụng Magick.NET. Đây là trình bao bọc C# cho 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"); 
}