2011-07-18 11 views
1

アニメーションGIFのサイズを変更するコードがあります。 コードを使用すると、イメージのサイズを常に小さくすることができます。 (今のところ大きくする必要はありません)アニメーション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にリサイズする必要がある場合は、フレームが類似している可能性がありますこの場合、各フレームは '比例的に'サイズ変更する必要があります。したがって、コードはforループの外側で 'グローバルに'比率を計算し、フレームあたりの比率を適用しています –

1

私はAtalasoft

で、私はこの覗き込む作業 - あなたのコードは絶対的に正しいですし、ちゃんとサイズの異なるフレーム上で動作します。あなたが計算しているポイントは正しいです。

問題は、3フレームGIFでは、2番目のフレームと3番目のフレームが正確に重ね合わされ、非常に複雑な透明マスクを使用して最初のフレームが表示されることです。イメージが新しいサイズにリサンプリングされると、マスクは正確ではなくなる可能性があります。幅と高さの1ピクセルの差にリサイズするため、このマスクが一致する可能性はありません。

は、この問題にはいくつかのソリューションがあります

  1. オーバーレイは、フレーム1の上枠2、その後、代わりに
  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(); 
    } 
関連する問題