Làm cách nào để tạo kết cấu XNA từ Ảnh GDI với hình chữ nhật nguồn?


8

Một Texture2D trong XNA chỉ có thể chứa rất nhiều. Tùy thuộc vào cấu hình nào tôi sử dụng giới hạn đó rộng 2048 hoặc 4096 pixel. Theo như tôi có thể nói từ nghiên cứu của mình (ai đó sửa tôi nếu tôi sai) Hình ảnh GDI không có bất kỳ giới hạn nào ngoài việc không vượt quá bộ nhớ của người dùng.

Tôi đang tìm cách hiệu quả nhất để chụp Ảnh GDI và hình chữ nhật nguồn (trong giới hạn kích thước của XNA) và tạo Texture2D mới từ dữ liệu đó khi chạy. Quá trình cũng phải tính đến alpha được nhân lên trước của XNA 4.0!

HOẶC LÀ...

Một cách để lấy Texture2D.FromStream và điều chỉnh nó sao cho nó cũng có một hình chữ nhật nguồn, vì điều đó sẽ còn tốt hơn cho nhu cầu của tôi.

Các yêu cầu là:

  • Không có đường ống nội dung, tôi cần có thể tải chúng khi chạy.
  • Chỉ sử dụng hồ sơ Reach nếu có thể!
  • Chỉ quan tâm đến Windows. Đừng lo lắng về tính di động.

TL; DR:

Tôi cần một phương pháp như:

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

Hoặc là

Texture2D Texture2DHelper.FromImage(Image, SourceRectangle)

Tốt nhất là đầu tiên.


Bức tranh lớn:

Bỏ qua hình chữ nhật nguồn trong giây lát (để giúp mọi thứ dễ hình dung hơn), tôi đã thử tải toàn bộ kết cấu trong GDI và chuyển dữ liệu tới Texture2D bằng cách sử dụng phương pháp hoàn toàn thô bạo:

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);
}

Và kết quả rất chậm. Phải mất nhiều thời gian hơn nhiều so với chỉ đơn giản là làm:

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

Tôi cũng đã nghĩ đến việc sử dụng Bitmap.LockBits và Block Copy nhưng làm như vậy sẽ loại bỏ được hiệu chỉnh alpha được nhân lên trước và tôi không biết làm thế nào để áp dụng nó sau khi sao chép.

Tôi muốn nghĩ rằng một giải pháp tốt hơn sẽ là làm việc trực tiếp với Texture2D.FromStream ... Tôi không quá quen thuộc với cách Stream hoạt động nhưng tôi đã thấy một số phương thức trong .NET sử dụng Stream và Hình chữ nhật. Làm thế nào tôi có thể đạt được một cái gì đó như thế? Phương thức FromStream hoàn toàn mới hoặc trình bao bọc xung quanh bất kỳ Luồng nào cung cấp chức năng "Hình chữ nhật".

Câu trả lời:


4

OK, quản lý để tìm giải pháp cho việc này, theo kiểu GDI! Tôi đã gói nó trong một lớp trợ giúp tĩnh:

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;
        }
    }
}

Trong trường hợp bạn không nhận thấy Texture2D.FromFile đã bị xóa khỏi XNA 4.0, vì vậy tôi đã có cơ hội sao chép hành vi cũ khi không chuyển qua hình chữ nhật nguồn.

Và phần tốt nhất là vì cuối cùng, nó vẫn dựa vào Texture2D.FromStream, toàn bộ giai đoạn alpha tiền xử lý được tự động hóa! Chạy tương đối nhanh quá. Được rồi, điều này không đúng! Bạn vẫn phải thực hiện các phép tính alpha sớm. Tôi chỉ không nhớ rõ vì tôi đã có mã để làm điều đó tại chỗ .

Nhưng vẫn tự hỏi liệu có cách nào để thực hiện việc này trực tiếp từ Luồng mà không phải thông qua GDI. Tâm trí lang thang về phía trang trí Suối theo một cách nào đó nhưng không đến được nơi nào. :)

Và từ khi duyệt qua mã cũ của tôi, tôi đã tìm thấy một nhận xét về Texture2D.FromStream bị lỗi và không thể đọc tất cả các định dạng mà tài liệu nói rằng, vì vậy tôi đã sử dụng GDI. Vì vậy, bây giờ tôi sẽ ở lại với phương pháp này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.