ソースの四角形を含むGDI画像からXNAテクスチャを作成する方法


8

XNAのTexture2Dが保持できるのはそれほど多くありません。使用するプロファイルに応じて、その制限は2048または4096ピクセル幅です。私の調査からわかる限り(私が間違っていれば誰かが訂正してくれます)GDI画像には、ユーザーのメモリを超えないこと以外に制限はありません。

(XNAのサイズ制限内で)GDI画像とソースの四角形を取得し、実行時にそのデータから新しいTexture2Dを作成する最も効率的な方法を探しています。このプロセスでは、XNA 4.0の乗算済みアルファも考慮に入れる必要があります。

または...

Texture2D.FromStreamを取得し、ソースレクタングルも取得できるようにそれを適応させる方法。

要件は次のとおりです。

  • コンテンツパイプラインはありません。実行時にそれらをロードできる必要があります。
  • 可能であれば、リーチプロファイルのみを使用してください。
  • Windowsのみに注意してください。移植性について心配する必要はありません。

TL; DR:

私は次のような方法が必要です:

Texture2D Texture2DHelper.FromStream(GraphicsDevice, Stream, SourceRectangle);

または

Texture2D Texture2DHelper.FromImage(Image, SourceRectangle)

できれば最初。


大局:

少しの間、ソースの四角形を無視して(物事を視覚化しやすくするために)、テクスチャ全体をGDIにロードし、完全にブルートフォースアプローチを使用してデータをTexture2Dに渡してみました。

using (System.Drawing.Image image = System.Drawing.Image.FromFile(path))
{
    int w = image.Width;
    int h = image.Height;
    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);
    uint[] data = new uint[w * h];
    for (int i=0; i!=bitmap.Width; ++i)
    {
        for (int j=0; j!=bitmap.Height; ++j)
        {
            System.Drawing.Color pixel = bitmap.GetPixel(i, j);
            Microsoft.Xna.Framework.Color color = Color.FromNonPremultiplied(pixel.R, pixel.G, pixel.B, pixel.A);
            data[i + j * w] = color.PackedValue;
        }
    }
    _texture = new Texture2D(device, w, h);
    _texture.SetData(data);
}

そして結果は本当に遅かった。単純に行うよりも何倍も時間がかかりました:

Texture2D.FromStream(GraphicsDevice, new FileStream(path, FileMode.Open));

Bitmap.LockBitsとBlock Copyの使用についても考えましたが、そうすると、乗算前のアルファ補正が省かれ、コピー後にそれを適用する方法がわかりません。

私は、Texture2D.FromStreamを直接回避する方が良い解決策になると考えたくなります。Streamのしくみにはあまり詳しくありませんが、.NETでStreamとRectangleを取得するメソッドをいくつか見ました。どうすればそのようなことを達成できますか?まったく新しいFromStreamメソッド、または「Rectangle」機能を提供するStreamのラッパー。

回答:


4

OK、GDIスタイルのソリューションを見つけました。私はそれを静的ヘルパークラスでラップしました:

public static class TextureLoader
{
    public static Texture2D FromFile(GraphicsDevice device, string path, Microsoft.Xna.Framework.Rectangle? sourceRectangle = null)
    {
        // XNA 4.0 removed FromFile in favor of FromStream
        // So if we don't pass a source rectangle just delegate to FromStream
        if(sourceRectangle == null)
        {
            return Texture2D.FromStream(device, new FileStream(path, FileMode.Open));
        }
        else
        {
            // If we passed in a source rectangle convert it to System.Drawing.Rectangle
            Microsoft.Xna.Framework.Rectangle xnaRectangle = sourceRectangle.Value;
            System.Drawing.Rectangle gdiRectangle = new System.Drawing.Rectangle(xnaRectangle.X, xnaRectangle.Y, xnaRectangle.Width, xnaRectangle.Height);

            // Start by loading the entire image
            Image image = Image.FromFile(path);

            // Create an empty bitmap to contain our crop
            Bitmap bitmap = new Bitmap(gdiRectangle.Width, gdiRectangle.Height, image.PixelFormat);

            // Draw the cropped image region to the bitmap
            Graphics graphics = Graphics.FromImage(bitmap);
            graphics.DrawImage(image, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), gdiRectangle.X, gdiRectangle.Y, gdiRectangle.Width, gdiRectangle.Height, GraphicsUnit.Pixel);

            // Save the bitmap into a memory stream
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, ImageFormat.Png);

            // Finally create the Texture2D from stream
            Texture2D texture = Texture2D.FromStream(device, stream);

            // Clean up
            stream.Dispose();
            graphics.Dispose();
            bitmap.Dispose();
            image.Dispose();

            return texture;
        }
    }
}

Texture2D.FromFileがXNA 4.0から削除されたことに気付かなかった場合は、ソースの四角形が渡されなかったときに古い動作を再現する機会を得ました。

そして、最良の部分は、最後には依然としてTexture2D.FromStreamに依存しているため、事前に乗算されたアルファ段階全体が自動化されていることです。比較的高速でも実行されます。 わかりました、これは真実ではありません!まだ、乗算前のアルファ計算を行う必要があります。私はすでにそれを実行するためのコードを持っているので、よく覚えていませんでした。

しかし、GDIを経由せずにStreamから直接これを行う方法があるかどうか疑問に思っています。心は何らかの方法でストリームの装飾に向かってさまよったが、どこにも届かなかった。:)

そして、私の古いコードを閲覧したところ、Texture2D.FromStreamにバグがあり、ドキュメントに記載されているすべての形式を読み取ることができないというコメントがあったので、とにかくGDIを使用しています。だから私は今のところこの方法を使い続けます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.