如何正确地将托管位图转换为非托管位图?

发布于 2024-10-15 18:46:57 字数 2018 浏览 1 评论 0原文

我正在尝试在 Visual C++.NET 2008 中使用 OpenGL 创建纹理立方体。 经过一番谷歌搜索后,使用 GLU,我发现我必须使用 gluBuild2DMipmaps。

问题是,我使用 System::Drawing::Bitmap.FromFile() 读取位图

现在,如何将此托管位图对象传递给 gluBuild2DMipmaps,它接受 const void * 参数???

我已经使用这些代码尝试了 LockBits:

BYTE * data;
/*ambil raw data*/
System::Drawing::Rectangle rect =  System::Drawing::Rectangle(0,0,b->Width,b->Height);
System::Drawing::Imaging::BitmapData ^  bitmapData;
    b->LockBits(
        rect,
        System::Drawing::Imaging::ImageLockMode::ReadWrite, 
        b->PixelFormat ,bitmapData);

    ::memcpy(data,bitmapData->Scan0.ToPointer(),b->Width * b->Height);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,
                   GL_RGB, GL_UNSIGNED_BYTE, data);

使用 24bpp BMP 文件,它卡在 lockbit 行上,并显示消息 System.ArgumentException:附加信息:参数无效。

我做错了什么???


我刚刚找到了正确的解决方案。这是因为有几个问题:

  1. 我使用了错误的重载函数。请参阅我调用 lockBits 的不同方式,
  2. 我没有初始化指针 dataBitmap
  3. 而且,由于 GLuint *texture; 是托管指针,我必须使用 pin_pointer 将其转换为非托管指针。

谢谢,这是正确的方法:

void CBox::LoadTextureRaw(String ^ filename, int wrap)
{
    //GLuint texture;

    System::Drawing::Bitmap ^ bitmap = gcnew Bitmap(filename);  
    int h = bitmap->Height;
    int w = bitmap->Width;
    int s = w * h;
    dataTexture = new BYTE[s * 3];

    System::Drawing::Rectangle rect =  System::Drawing::Rectangle(0,0,bitmap->Width,bitmap->Height);
    System::Drawing::Imaging::BitmapData ^  bitmapData = 
        bitmap->LockBits(rect,System::Drawing::Imaging::ImageLockMode::ReadWrite , System::Drawing::Imaging::PixelFormat::Format24bppRgb);

    ::memcpy(dataTexture,bitmapData->Scan0.ToPointer(),s);


    bitmap->UnlockBits(bitmapData); 
    pin_ptr<GLuint*> pt = &texture;//pin managed pointer, to be unmanaged... asyeeeem
    **pt = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h,GL_RGB, GL_UNSIGNED_BYTE, dataTexture);     
}

I am trying to create a textured Cube using OpenGL in Visual C++.NET 2008.
After some googgling, using GLU, I found that I must use gluBuild2DMipmaps.

The problem Is, I read the bitmap using System::Drawing::Bitmap.FromFile()

Now, How do I pass this managed Bitmap object to gluBuild2DMipmaps, which accept const void * parameter???

I already try the LockBits using these code:

BYTE * data;
/*ambil raw data*/
System::Drawing::Rectangle rect =  System::Drawing::Rectangle(0,0,b->Width,b->Height);
System::Drawing::Imaging::BitmapData ^  bitmapData;
    b->LockBits(
        rect,
        System::Drawing::Imaging::ImageLockMode::ReadWrite, 
        b->PixelFormat ,bitmapData);

    ::memcpy(data,bitmapData->Scan0.ToPointer(),b->Width * b->Height);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,
                   GL_RGB, GL_UNSIGNED_BYTE, data);

Using a 24bpp BMP file, it stuck on the line lockbit with message System.ArgumentException : Additional information: Parameter is not valid.

What did I do wrong????


I just found the correct solution. It's because a couple of problem:

  1. I use the wrong overloaded function. See the different in how I call lockBits
  2. I am not initializing the pointer dataBitmap.
  3. And also, as GLuint * texture; is a managed pointer, I must convert it into unmanaged pointer using pin_pointer.

Thanks, and this is the correct method :

void CBox::LoadTextureRaw(String ^ filename, int wrap)
{
    //GLuint texture;

    System::Drawing::Bitmap ^ bitmap = gcnew Bitmap(filename);  
    int h = bitmap->Height;
    int w = bitmap->Width;
    int s = w * h;
    dataTexture = new BYTE[s * 3];

    System::Drawing::Rectangle rect =  System::Drawing::Rectangle(0,0,bitmap->Width,bitmap->Height);
    System::Drawing::Imaging::BitmapData ^  bitmapData = 
        bitmap->LockBits(rect,System::Drawing::Imaging::ImageLockMode::ReadWrite , System::Drawing::Imaging::PixelFormat::Format24bppRgb);

    ::memcpy(dataTexture,bitmapData->Scan0.ToPointer(),s);


    bitmap->UnlockBits(bitmapData); 
    pin_ptr<GLuint*> pt = &texture;//pin managed pointer, to be unmanaged... asyeeeem
    **pt = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h,GL_RGB, GL_UNSIGNED_BYTE, dataTexture);     
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空心空情空意 2024-10-22 18:46:57

我使用以下代码来复制位图数据:

Image image = null;
Bitmap iBitmap = new Bitmap(fs);
BitmapData iBitmapData;
GCHandle hImageData;

if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceRgb) != 0) {
    switch (iBitmap.PixelFormat) {
        case PixelFormat.Format1bppIndexed:
        case PixelFormat.Format4bppIndexed:
        case PixelFormat.Format8bppIndexed:
            // Allocate image raster
            image = new RasterImage<ColorBGR8>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format16bppRgb565:
            // Allocate image raster
            image = new RasterImage<ColorBGR16>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format24bppRgb:
            // Allocate image raster
            image = new RasterImage<ColorBGR24>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format32bppRgb:
            // Allocate image raster
            image = new RasterImage<ColorBGR32>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format32bppArgb:
            // Allocate image raster
            image = new RasterImage<ColorABGR32>(iBitmap.Width, iBitmap.Height);
            break;
        default:
            throw new Exception("Image RGB pixel format not supported");
    }
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceGray) != 0) {
    switch (iBitmap.PixelFormat) {
        case PixelFormat.Format1bppIndexed:
        case PixelFormat.Format4bppIndexed:
        case PixelFormat.Format8bppIndexed:
            // Allocate image raster
            image = new RasterImage<ColorY8>(iBitmap.Width, iBitmap.Height);
            break;
        default:
            throw new Exception("Image GRAY pixel format not supported");
    }

    if (RenderContext.Caps.TextureSwizzle == false) {
        throw new Exception("unable to load GRAY pixel format image (ARB_texture_swizzle extension not supported)");
    }
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceYcbcr) != 0) {
    throw new Exception("Image YCbCr pixel format not supported");
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceYcck) != 0) {
    throw new Exception("Image YCCK pixel format not supported");
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceCmyk) != 0) {
    throw new Exception("Image CMYK pixel format not supported");
} else
    throw new Exception("Image pixel format not supported");

// Obtain source and destination data pointers
iBitmapData = iBitmap.LockBits(new Rectangle(0, 0, iBitmap.Width, iBitmap.Height), ImageLockMode.ReadOnly, iBitmap.PixelFormat);
hImageData = GCHandle.Alloc(image.GetPixelData(), GCHandleType.Pinned);

    // Alternative without using custom Image class:
    //T[,] buffer = new ColorRGB24[iBitmap.Width, iBitmap.Height];
    //hImageData = GCHandle.Alloc(buffer, GCHandleType.Pinned);

// Copy Bitmap data to Image
memcpy(hImageData.AddrOfPinnedObject(), iBitmapData.Scan0, iBitmapData.Stride*iBitmapData.Height);

hImageData.Free();
iBitmap.UnlockBits(iBitmapData);

return (image);

您可以注意到我必须 P/Invoke memcpy 例程来复制锁定的内存。

Image 类是在我的项目中定义的类,它将方法 GetPixelData() 定义为返回 T[,] 的简单例程,其中 T 是如下所示的结构

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ColorRGB24 : IColorRGB<byte>
{
    public byte r;
    public byte g;
    public byte b;
}

请阅读以下引用:

Using System.Drawing.Imaging.PixelFormat values, such as Indexed and Gdi, will throw an System.ArgumentException

因此,请确保没有 IndexedGdi 像素格式值。

I use the following code to copy Bitmap data:

Image image = null;
Bitmap iBitmap = new Bitmap(fs);
BitmapData iBitmapData;
GCHandle hImageData;

if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceRgb) != 0) {
    switch (iBitmap.PixelFormat) {
        case PixelFormat.Format1bppIndexed:
        case PixelFormat.Format4bppIndexed:
        case PixelFormat.Format8bppIndexed:
            // Allocate image raster
            image = new RasterImage<ColorBGR8>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format16bppRgb565:
            // Allocate image raster
            image = new RasterImage<ColorBGR16>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format24bppRgb:
            // Allocate image raster
            image = new RasterImage<ColorBGR24>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format32bppRgb:
            // Allocate image raster
            image = new RasterImage<ColorBGR32>(iBitmap.Width, iBitmap.Height);
            break;
        case PixelFormat.Format32bppArgb:
            // Allocate image raster
            image = new RasterImage<ColorABGR32>(iBitmap.Width, iBitmap.Height);
            break;
        default:
            throw new Exception("Image RGB pixel format not supported");
    }
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceGray) != 0) {
    switch (iBitmap.PixelFormat) {
        case PixelFormat.Format1bppIndexed:
        case PixelFormat.Format4bppIndexed:
        case PixelFormat.Format8bppIndexed:
            // Allocate image raster
            image = new RasterImage<ColorY8>(iBitmap.Width, iBitmap.Height);
            break;
        default:
            throw new Exception("Image GRAY pixel format not supported");
    }

    if (RenderContext.Caps.TextureSwizzle == false) {
        throw new Exception("unable to load GRAY pixel format image (ARB_texture_swizzle extension not supported)");
    }
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceYcbcr) != 0) {
    throw new Exception("Image YCbCr pixel format not supported");
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceYcck) != 0) {
    throw new Exception("Image YCCK pixel format not supported");
} else if ((iBitmap.Flags & (int)ImageFlags.ColorSpaceCmyk) != 0) {
    throw new Exception("Image CMYK pixel format not supported");
} else
    throw new Exception("Image pixel format not supported");

// Obtain source and destination data pointers
iBitmapData = iBitmap.LockBits(new Rectangle(0, 0, iBitmap.Width, iBitmap.Height), ImageLockMode.ReadOnly, iBitmap.PixelFormat);
hImageData = GCHandle.Alloc(image.GetPixelData(), GCHandleType.Pinned);

    // Alternative without using custom Image class:
    //T[,] buffer = new ColorRGB24[iBitmap.Width, iBitmap.Height];
    //hImageData = GCHandle.Alloc(buffer, GCHandleType.Pinned);

// Copy Bitmap data to Image
memcpy(hImageData.AddrOfPinnedObject(), iBitmapData.Scan0, iBitmapData.Stride*iBitmapData.Height);

hImageData.Free();
iBitmap.UnlockBits(iBitmapData);

return (image);

You can note I had to P/Invoke memcpy routine to copy locked memory.

The Image class is a class defined in my project, which defines the method GetPixelData() as a simple routine returning a T[,], where T is a structure like the following

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ColorRGB24 : IColorRGB<byte>
{
    public byte r;
    public byte g;
    public byte b;
}

Read the following quote:

Using System.Drawing.Imaging.PixelFormat values, such as Indexed and Gdi, will throw an System.ArgumentException

So, make sure to do not have the Indexed or Gdi pixel format values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文