2011-07-18 78 views
1

我有一段代碼來調整動畫gif的大小。 如果它有助於代碼將始終將圖像調整爲較小的尺寸。 (現在沒有必要讓它們變大)使用dotimage調整動畫gif的大小

我正在使用Atalasoft的dotimage庫和它們的示例代碼來進行實際的重採樣。 代碼應該從磁盤讀取動畫gif,遍歷幀並將每個幀重新調整爲新的大小。 當gif動畫包含相同大小的幀但調整大小不同的幀的動畫時,此工作正常中斷動畫(調整後幀不會正確重疊),我認爲這是因爲代碼沒有計算新的正確偏移。

我認爲這是一行代碼,它不計算右邊的偏移量: Point point = new Point((int)(frame.Location.X * ratio),(int)(frame.Location.Y * ratio ));

下面是完整的調整大小常規:

static private void GenerateGifImage(FileStream fileStream, int OutputWidth, int OutputHeight) 
    {    
     // MemoryStream InputStream = new MemoryStream(); 
     FileStream InputStream = fileStream; 
     // fileStream.Write(InputStream.GetBuffer(), 0, (int)InputStream.Position); 
     // InputStream.Seek(0, SeekOrigin.Begin); 
     Image InputImage = Image.FromStream(InputStream, true, false); 

     // this will invalidate the underlying image object in InputImage but the class properties 
     // will still accessible until the object is disposed 
     InputStream.Seek(0, SeekOrigin.Begin); 

     ImageInfo imageInfo = RegisteredDecoders.GetImageInfo(InputStream); 
     InputStream.Seek(0, SeekOrigin.Begin); 

     GifDecoder gifDecoder = new GifDecoder(); 
     int count = gifDecoder.GetFrameCount(InputStream); 

     GifFrameCollection gifFrameCollection = new GifFrameCollection(); 
     gifFrameCollection.Height = OutputHeight; 
     gifFrameCollection.Width = OutputWidth; 
     // gifFrameCollection.Height = gifDecoder.Frames.Height; 
     // gifFrameCollection.Width = gifDecoder.Frames.Width; 

     double ratio; 
     if (InputImage.Height > InputImage.Width) 
     { 
      ratio = (double)OutputHeight/(double)InputImage.Height; 
     } 
     else 
     { 
      ratio = (double)OutputWidth/(double)InputImage.Width; 
     } 

     for (int i = 0; i < count; i++) 
     { 
      GifFrame frame = gifDecoder.Frames[i]; 

      Rectangle rectangle = new Rectangle(Point.Empty, frame.Image.Size); 

      int frameWidth = (int)(frame.Image.Width * ratio); 
      int frameHeight = (int)(frame.Image.Height * ratio); 

      // account for erratic rounding, seems illogical but has happened earlier when using floats instead of doubles 
      if (frameWidth > OutputWidth) 
      { 
       frameWidth = OutputWidth; 
      } 
      if (frameHeight > OutputHeight) 
      { 
       frameHeight = OutputHeight; 
      } 

      Size size = new Size(frameWidth, frameHeight); 
      // only resize if we have a measureable dimension 
      if (size.Width > 0 && size.Height > 0) 
      { 
       // ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.NearestNeighbor); 
       ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.NearestNeighbor); 
       AtalaImage atalaImage = resampleCommand.Apply(frame.Image).Image; 
       // save the image for debugging 
       // atalaImage.Save("frame" + i.ToString() + ".gif", ImageType.Gif, null); 
       // frame.Image.Save("frame-orig" + i.ToString() + ".gif", ImageType.Gif, null); 

       // AtalaImage atalaImage = frame.Image; 
       Point point = new Point((int)(frame.Location.X * ratio), (int)(frame.Location.Y * ratio)); 
       // Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); 
       gifFrameCollection.Add(new GifFrame(atalaImage, point, frame.DelayTime, frame.Interlaced, frame.FrameDisposal, frame.TransparentIndex, frame.UseLocalPalette)); 
      } 
     } 
     FileStream saveStream = new FileStream("resized.gif", FileMode.Create, FileAccess.Write, FileShare.Write); 
     GifEncoder gifSave = new GifEncoder(); 
     gifSave.Save(saveStream, gifFrameCollection, null); 
     saveStream.Close(); 
    } 

回答

0

比率的計算值是不正確的,如果你與不同的幀大小的工作。您應該計算每個框架的比率,以便您關注的線條使用正確的比例。我對這個框架並不熟悉,所以我不能給你一個準確的例子。但它應該類似於此:

GifFrame frame = gifDecoder.Frames[i]; 
double frameRatio; 
if (frame.Height > frame.Width) 
{ 
    frameRatio = (double)OutputHeight/(double)frame.Height; 
} 
else 
{ 
    frameRatio = (double)OutputWidth/(double)frame.Width; 
} 

... 

Point point = new Point((int)(frame.Location.X * frameRatio), (int)(frame.Location.Y * frameRatio)); 
+0

我明白了,我沒有考慮x和y偏移。 – Kolky

+0

我試着重新計算每幀的比率,然後重新採樣每一幀,但結果偏移量和圖像大小跨過gif動畫的大小。在上面的代碼中,假設每幀將被調整爲OutputWidth,則計算比率 - 如果gif動畫是480 x 120並且我們必須將其大小調整爲479 x 119,那麼可能會有幀80 x 20(用xy偏移來對齊它)在這種情況下,每幀必須按比例調整大小,因此代碼是在for循環外部「全局」計算比率並應用每幀比率 –

1

我工作的Atalasoft

我看着這一點 - 你的代碼是完全正確和大小不等蠻好的框架是可行的。你正在計算的點是正確的。

問題是,在你的3幀GIF中,你的第二幀和第三幀被精確地疊加在第一幀的頂部,並使用非常複雜的透明蒙板來顯示通過它們的第一幀。當您的圖像被重新採樣到一個新的大小,面具可能不再是精確的 - 因爲你的寬度和高度只是一個像素的差異,這個面具無法匹配。

有幾種解決這個問題

  1. 覆蓋幀2到第1幀,然後重新採樣並使用該圖像,而不是
  2. 做#1,但隨後提取幀2
  3. 使用的矩形作物而不是重新採樣 - 這看起來最好,因爲它只有1個像素。

我編寫了#3你 - 它工作得很好

static private void GenerateGifImage(FileStream fileStream, int OutputWidth, int OutputHeight) 
    {    
     // MemoryStream InputStream = new MemoryStream(); 
     FileStream InputStream = fileStream; 
     // fileStream.Write(InputStream.GetBuffer(), 0, (int)InputStream.Position); 
     // InputStream.Seek(0, SeekOrigin.Begin); 
     Image InputImage = Image.FromStream(InputStream, true, false); 

     // this will invalidate the underlying image object in InputImage but the class properties 
     // will still accessible until the object is disposed 
     InputStream.Seek(0, SeekOrigin.Begin); 

     ImageInfo imageInfo = RegisteredDecoders.GetImageInfo(InputStream); 
     InputStream.Seek(0, SeekOrigin.Begin); 

     GifDecoder gifDecoder = new GifDecoder(); 
     int count = gifDecoder.GetFrameCount(InputStream); 

     GifFrameCollection gifFrameCollection = new GifFrameCollection(); 
     gifFrameCollection.Height = OutputHeight; 
     gifFrameCollection.Width = OutputWidth; 

     double ratio; 
     if (InputImage.Height > InputImage.Width) 
     { 
      ratio = (double)OutputHeight/(double)InputImage.Height; 
     } 
     else 
     { 
      ratio = (double)OutputWidth/(double)InputImage.Width; 
     } 

     for (int i = 0; i < count; i++) 
     { 
      GifFrame frame = gifDecoder.Frames[i]; 

      Rectangle rectangle = new Rectangle(Point.Empty, frame.Image.Size); 

      int newframeWidth = frame.Image.Width; 
      int newframeHeight = frame.Image.Height; 
      if (newframeWidth > OutputWidth || newframeHeight > OutputHeight) 
      { 
       newframeWidth = (int)(frame.Image.Width * ratio); 
       newframeHeight = (int)(frame.Image.Height * ratio); 
      } 

      // account for erratic rounding, seems illogical but has happened earlier when using floats instead of doubles 
      if (newframeWidth > OutputWidth) 
      { 
       newframeWidth = OutputWidth; 
      } 
      if (newframeHeight > OutputHeight) 
      { 
       newframeHeight = OutputHeight; 
      } 

      Size size = new Size(newframeWidth, newframeHeight); 
      // only resize if we have a measureable dimension 
      if (size.Width > 0 && size.Height > 0) 
      { 
       //ResampleCommand resampleCommand = new ResampleCommand(rectangle, size, ResampleMethod.); 
       AtalaImage atalaImage = frame.Image; 
       if (newframeWidth != frame.Image.Width || newframeHeight != frame.Image.Height) 
       { 
        CropCommand command = new CropCommand(new Rectangle(new Point(0, 0), size)); 
        atalaImage = command.Apply(frame.Image).Image; 
       } 
       // AtalaImage atalaImage = frame.Image; 
       Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); 
       // Point point = new Point((int)(frame.Location.X), (int)(frame.Location.Y)); 
       gifFrameCollection.Add(new GifFrame(atalaImage, point, frame.DelayTime, frame.Interlaced, frame.FrameDisposal, frame.TransparentIndex, frame.UseLocalPalette)); 
      } 
     } 
     FileStream saveStream = new FileStream("resized.gif", FileMode.Create, FileAccess.Write, FileShare.Write); 
     GifEncoder gifSave = new GifEncoder(); 
     gifSave.Save(saveStream, gifFrameCollection, null); 
     saveStream.Close(); 
    }