1

アニメーション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();
    }
4

2 に答える 2

1

私はアタラソフトで働いています

私はこれを調べました-あなたのコードは完全に正しく、サイズが異なるフレームでも問題なく動作します。あなたが計算している点は正しいです。

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

この問題にはいくつかの解決策があります

  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();
    }
于 2011-07-22T19:56:55.467 に答える
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));
于 2011-07-18T11:49:55.967 に答える