2012-04-27 4 views
7

मैं टीजीआईएफआईमेज का उपयोग कर रहा हूं जो डेल्फी एक्सई के साथ शामिल है।टीजीआईफ़ीमेज पारदर्शिता समस्या

जो मैं करने की कोशिश कर रहा हूं वह एक फ़ाइल से एक गिफ लोड करता है और सभी फ्रेम को बिटमैप में निकाला जाता है।

यह मैं अब तक क्या किया है:

procedure ExtractGifFrames(FileName: string); 
var 
    Gif: TGifImage; 
    Bmp: TBitmap; 
    i: Integer; 
begin 
    Gif := TGifImage.Create; 
    try 
    Gif.LoadFromFile(FileName); 

    Bmp := TBitmap.Create; 
    try 
     Bmp.SetSize(Gif.Width, Gif.Height); 

     for i := 0 to Gif.Images.Count - 1 do 
     begin 
     if not Gif.Images[i].Empty then 
     begin 
      Bmp.Assign(Gif.Images[i]); 
      Bmp.SaveToFile('C:\test\bitmap' + IntToStr(i) + '.bmp'); 
     end; 
     end; 
    finally 
     Bmp.Free; 
    end; 
    finally 
    Gif.Free; 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if OpenPictureDialog1.Execute then 
    begin 
    ExtractGifFrames(OpenPictureDialog1.FileName); 
    end; 
end; 

समस्या का सामना करना पड़ रहा हूँ अलग Gifs का एक बहुत के साथ कुछ पारदर्शिता मुद्दा है, और भी आकार की समस्याओं के साथ है।

यहाँ है कि ऊपर मेरी कोड का उपयोग कर बचा लिया गया कुछ उदाहरण बिटमैप्स हैं:

enter image description here enter image description here

आप परिणाम महान नहीं कर रहे हैं देख सकते हैं, वे आकार और पारदर्शिता मुद्दे हैं।

मुझे पता है कि GIF फ़ाइलें स्वयं भ्रष्ट नहीं हैं, क्योंकि मैं उन्हें अपने वेब ब्राउज़र के माध्यम से लोड कर सकता हूं और वे बिना किसी दोष के सही तरीके से प्रदर्शित होते हैं।

मैं फ़ाइल से एक गिफ कैसे लोड कर सकता हूं, किसी भी गुणवत्ता को खोए बिना बिटमैप को प्रत्येक फ्रेम असाइन कर सकता हूं?

+2

मैं जिस तरह से कैसे कुंजी फ्रेम महसूस कर रहे हैं पता चला। यह प्रत्येक फ्रेम (यदि उपलब्ध हो) के लिए 'GraphicControlExtension.Disposal' द्वारा निर्धारित किया जाता है। इसका मतलब है कि मौजूदा फ्रेम पहले से ही प्रस्तुत बफर के साथ क्या करना चाहिए। एक स्रोत के रूप में आप 'TGIFRenderer' से अधिक का उपयोग कर सकते हैं, वह कक्षा जो वास्तव में एनिमेशन प्रदान करती है। मैं शाम को एक उदाहरण लिखने की कोशिश करूंगा (यदि कोई तेज़ नहीं होगा :-) मुझे अब जाना है ... – TLama

उत्तर

10

पुराने डेल्फी संस्करणों के लिए (पूर्व 2009):GIFImage इकाई के कोड पर एक नजर डालें, तो आप कैसे TGIFPainter प्रत्येक फ्रेम के Disposal पद्धति पर आधारित छवियों renders जाँच करना चाहते हो सकता है।

मैंने बीएमपी को सक्रिय फ्रेम को बचाने के लिए TGIFPainter.OnAfterPaint इवेंट हैंडलर का उपयोग करने वाला एक छोटा कोड लिखा है, और सभी "कड़ी मेहनत" करते हैं।

नोट: GIFImage इकाई संस्करण 2.2 रिलीज: 5 (23-मई-1999)

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    ProgressBar1: TProgressBar; 
    procedure Button1Click(Sender: TObject); 
    public 
    FBitmap: TBitmap; 
    procedure AfterPaintGIF(Sender: TObject); 
    end; 

... 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    GIF: TGIFImage; 
begin 
    GIF := TGIFImage.Create; 
    FBitmap := TBitmap.Create; 
    Button1.Enabled := False; 
    try 
    GIF.LoadFromFile('c:\test\test.gif'); 
    GIF.DrawOptions := GIF.DrawOptions - [goLoop, goLoopContinously, goAsync]; 
    GIF.AnimationSpeed := 1000; // Max - no delay 
    FBitmap.Width := GIF.Width; 
    FBitmap.Height := GIF.Height; 
    GIF.OnAfterPaint := AfterPaintGIF; 

    ProgressBar1.Max := Gif.Images.Count; 
    ProgressBar1.Position := 0; 
    ProgressBar1.Smooth := True; 
    ProgressBar1.Step := 1; 

    // Paint the GIF onto FBitmap, Let TGIFPainter do the painting logic 
    // AfterPaintGIF will fire for each Frame 
    GIF.Paint(FBitmap.Canvas, FBitmap.Canvas.ClipRect, GIF.DrawOptions); 
    ShowMessage('Done!'); 
    finally 
    FBitmap.Free; 
    GIF.Free; 
    Button1.Enabled := True; 
    end; 
end; 

procedure TForm1.AfterPaintGIF(Sender: TObject); 
begin 
    if not (Sender is TGIFPainter) then Exit; 
    if not Assigned(FBitmap) then Exit; 
    // The event will ignore Empty frames  
    FBitmap.Canvas.Lock; 
    try 
    FBitmap.SaveToFile(Format('%.2d.bmp', [TGIFPainter(Sender).ActiveImage])); 
    finally 
    FBitmap.Canvas.Unlock; 
    end; 
    ProgressBar1.StepIt; 
end; 

नोट: कोड को आसान बनाने से निपटने कोई त्रुटि।

output bitmaps


नए डेल्फी संस्करण (2009+) के लिए: के साथ निर्माण में GIFImg इकाई, तो आप इस TGIFRenderer के उपयोग के साथ आसान छोड़ने (जो पूरी तरह से बदल दिया वर्ष TGIFPainter) जैसे कर सकते हैं:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    GIF: TGIFImage; 
    Bitmap: TBitmap; 
    I: Integer; 
    GR: TGIFRenderer; 
begin 
    GIF := TGIFImage.Create;  
    Bitmap := TBitmap.Create; 
    try 
    GIF.LoadFromFile('c:\test\test.gif'); 
    Bitmap.SetSize(GIF.Width, GIF.Height); 
    GR := TGIFRenderer.Create(GIF); 
    try 
     for I := 0 to GIF.Images.Count - 1 do 
     begin 
     if GIF.Images[I].Empty then Break; 
     GR.Draw(Bitmap.Canvas, Bitmap.Canvas.ClipRect); 
     GR.NextFrame; 
     Bitmap.SaveToFile(Format('%.2d.bmp', [I])); 
     end; 
    finally 
     GR.Free; 
    end; 
    finally 
    GIF.Free; 
    Bitmap.Free; 
    end; 
end; 

का उपयोग GDI +:

uses ..., GDIPAPI, GDIPOBJ, GDIPUTIL; 

procedure ExtractGifFrames(const FileName: string); 
var 
    GPImage: TGPImage; 
    encoderClsid: TGUID; 
    BmpFrame: TBitmap; 
    MemStream: TMemoryStream; 
    FrameCount, FrameIndex: Integer; 
begin 
    GPImage := TGPImage.Create(FileName); 
    try 
    if GPImage.GetLastStatus = Ok then 
    begin 
     GetEncoderClsid('image/bmp', encoderClsid); 
     FrameCount := GPImage.GetFrameCount(GDIPAPI.FrameDimensionTime); 
     for FrameIndex := 0 to FrameCount - 1 do 
     begin 
     GPImage.SelectActiveFrame(GDIPAPI.FrameDimensionTime, FrameIndex); 
     MemStream := TMemoryStream.Create; 
     try 
      if GPImage.Save(TStreamAdapter.Create(MemStream), encoderClsid) = Ok then 
      begin 
      MemStream.Position := 0; 
      BmpFrame := TBitmap.Create; 
      try 
       BmpFrame.LoadFromStream(MemStream); 
       BmpFrame.SaveToFile(Format('%.2d.bmp', [FrameIndex])); 
      finally 
       BmpFrame.Free; 
      end; 
      end; 
     finally 
      MemStream.Free; 
     end; 
     end; 
    end; 
    finally 
    GPImage.Free; 
    end; 
end; 
+1

उत्कृष्ट, दूसरा उदाहरण मेरे लिए पूरी तरह से काम करता है (डेल्फी एक्सई)। काश मैं इस परिदृश्य में कई उत्तरों को स्वीकार कर सकता हूं, सभी को धन्यवाद। इस कोड का अध्ययन करने से मुझे लगता है कि यह अपेक्षाकृत आसान दिखता है। –

+5

+1, मुझे लगता है कि प्रस्तुतकर्ता का उपयोग करना ऐसा करने का सबसे स्वाभाविक तरीका है। – TLama

2

एनिमेटेड जीआईएफ फ़ाइल के फ्रेम में अक्सर पिछले फ्रेम (फ़ाइल आकार को कम करने के लिए अनुकूलन तकनीक) से भिन्नताएं होती हैं। तो किसी विशेष बिंदु पर जीआईएफ का एक स्नैपशॉट तैयार करने के लिए, आपको सभी फ्रेम को उस बिंदु तक पेस्ट करना होगा, एक के बाद एक। एनिमेटेड GIF प्रारूप है, जो बार फ्रेम की राशि का उल्लेख करना अन्य तत्वों रहे हैं दोहराया जाना जाता है:

procedure ExtractGifFrames(FileName: string); 
var 
    Gif: TGifImage; 
    Bmp: TBitmap; 
    i: Integer; 
    Bounds: TRect; 
begin 
    Gif := TGifImage.Create; 
    try 
    Gif.LoadFromFile(FileName); 
    Bounds := Rect(0, 0, Gif.Width-1, Gif.Height-1); 

    Bmp := TBitmap.Create; 
    try 
     Bmp.SetSize(Gif.Width, Gif.Height); 
     Bmp.PixelFormat := pf32bit; 

     for i := 0 to Gif.Images.Count - 1 do 
     begin 
     if not Gif.Images[i].Empty then 
     begin 
      Gif.Images[i].Draw(Bmp.Canvas, Bounds, True, True); 
      Bmp.SaveToFile(IntToStr(i) + '.bmp'); 
     end; 
     end; 
    finally 
     Bmp.Free; 
    end; 
    finally 
    Gif.Free; 
    end; 
end; 

एनबी:

हम अपनी 'पारदर्शी रूप से आकर्षित' विकल्प सेट के साथ Draw() का उपयोग करके इस लक्ष्य को हासिल कर सकते हैं आदि लेकिन वे आपको चिंता नहीं कर सकते हैं।

+0

मैं उल्लेख करना भूल गया कि मैंने पहले ही कोशिश की है, कोई फर्क नहीं पड़ता। ऐसा लगता है कि एक gif में कुछ फ्रेम केवल अतिरिक्त बिट्स खींचते हैं, और पृष्ठभूमि को आकर्षित करने के लिए पिछले फ्रेम का उपयोग करते हैं? –

+0

ठीक है, मेरे उत्तर में संशोधन किया है :-) –

+0

मैं वास्तव में आखिरी टिप्पणी के बारे में बंद था! यकीन नहीं है कि मैं इसे कैसे प्राप्त कर सकता हूं? –