2
\$\begingroup\$

I currently have an image processing application that outputs processed images post pixel shaders have been applied. However, using the examples I've found on the internet, the colors are flip to BGRA when RGBA is expected. I currently work around this with by post export processing to get the desired RGBA format. I was hoping someone else has dealt with this and has a solution that does not require post processing to correct the format.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

I have two methods for doing this I will post them both.

Code is in VB.net and using sharpDX 3.0.2

Basically you copy your texture data to a staging resource and then write that staging resource to disk using WIC.

If I recall I may have pulled this out of the SharpDX.Toolkit, DrawContext is just a wrapper around Device context so it should just be a name change and it will work.

This will save textures to disk as DDS files, you can change this by changing out the WIC encoder or load the images into Photoshop and do it from there.

  ' jpeg Container Format GUID: 19e4a5aa-5662-4fc5-a0c01758028e1057
  ' PNG Container Format GUID: 1b7cfaf4-713f-473c-bbcd6137425faeaf

 Dim blah As Guid = Guid.Parse("9967cb952E854ac88ca283d7ccd425c9") 'this is the WIC DDS Container Format GUID


 Dim bitmapEncoder As DdsEncoder = New DdsEncoder 'This is the WIC DDS encoder, try changing this to png or jpeg.

I like the DDS file format so I just stick with that.

How to save a texture to a File

   Dim fs As New FileStream(DirectXDevice.ContentPath & "Textures\Layer1.dds", FileMode.OpenOrCreate)
        SaveTexture(_Context, TerrainLayerBuffer, fs)
        fs.Flush()
        fs.Dispose()

How to save a texture to a System.Drawing.Image

 Dim ms As New MemoryStream()

 SaveTexture(_Context, TerrainLayerBuffer, ms)
 ms.Flush()

 Dim newimage As System.Drawing.Image = System.Drawing.Image.FromStream(ms)
 ms.Dispose()

The save texture methods

  Public Sub SaveTexture(_device As DrawContext, res As Resource,ByRef stream As Stream)
    Dim factory As New ImagingFactory()
    Dim texture = TryCast(res, Texture2D)
    'Setup Staging resource
    Dim textureCopy = New Texture2D(_device.Device, New Texture2DDescription() With {
    .Width = CType(texture.Description.Width, Integer),
    .Height = CType(texture.Description.Height, Integer),
    .MipLevels = 1,
    .ArraySize = 1,
    .Format = texture.Description.Format,
    .Usage = ResourceUsage.Staging,
    .SampleDescription = New SharpDX.DXGI.SampleDescription(1, 0),
    .BindFlags = BindFlags.None,
    .CpuAccessFlags = CpuAccessFlags.Read,
    .OptionFlags = ResourceOptionFlags.None
})
     Copy Texture Data To Staging Resource
    _device.CopyResource(res, textureCopy)

    'Read Staging resource data to a Datastream to be passed to the WIC codec
    Dim dataStream As DataStream
    Dim dataBox = _device.MapSubresource(textureCopy, 0, 0, MapMode.Read, Direct3D11.MapFlags.None, dataStream)

    Dim dataRectangle = New DataRectangle() With {
    .DataPointer = dataStream.DataPointer,
    .Pitch = dataBox.RowPitch
}

    ' TODO: should use some conversion from textureCopy.Description.Format
    Dim bitmap As BitmapSource = New Bitmap(factory, textureCopy.Description.Width, textureCopy.Description.Height, PixelFormatFromFormat(textureCopy.Description.Format), dataRectangle)

    'Set Up WIC
    Using WICStream As New WICStream(factory, stream)
        Dim blah As Guid = Guid.Parse("9967cb952E854ac88ca283d7ccd425c9") 'DDS Container Format
        Dim bitmapEncoder As BitmapEncoder = New BitmapEncoder(factory, blah, WICStream)
        Dim ccc As BitmapEncoderInfo = bitmapEncoder.EncoderInfo

        If bitmapEncoder IsNot Nothing Then
            Using bitmapFrameEncode = New BitmapFrameEncode(bitmapEncoder)

                bitmapFrameEncode.Initialize()
                bitmapFrameEncode.SetSize(bitmap.Size.Width, bitmap.Size.Height)

                bitmapFrameEncode.SetPixelFormat(PixelFormatFromFormat(textureCopy.Description.Format))
                bitmapFrameEncode.WriteSource(bitmap)
                bitmapFrameEncode.Commit()
                bitmapEncoder.Commit()
            End Using
            bitmapEncoder.Dispose()
        End If
    End Using

    _device.UnmapSubresource(textureCopy, 0)

    "Clean UP
    textureCopy.Dispose()
    bitmap.Dispose()
    factory.Dispose()


End Sub


  Public Sub SaveTexture(_device As DrawContext, res As Resource, _filename As String)
    Dim factory As New ImagingFactory()
    Dim texture = TryCast(res, Texture2D)
    Dim textureCopy = New Texture2D(_device.Device, New Texture2DDescription() With {
    .Width = CType(texture.Description.Width, Integer),
    .Height = CType(texture.Description.Height, Integer),
    .MipLevels = 1,
    .ArraySize = 1,
    .Format = texture.Description.Format,
    .Usage = ResourceUsage.Staging,
    .SampleDescription = New SharpDX.DXGI.SampleDescription(1, 0),
    .BindFlags = BindFlags.None,
    .CpuAccessFlags = CpuAccessFlags.Read,
    .OptionFlags = ResourceOptionFlags.None
})
    _device.CopyResource(res, textureCopy)

    Dim dataStream As DataStream
    Dim dataBox = _device.MapSubresource(textureCopy, 0, 0, MapMode.Read, Direct3D11.MapFlags.None, dataStream)

    Dim dataRectangle = New DataRectangle() With {
    .DataPointer = dataStream.DataPointer,
    .Pitch = dataBox.RowPitch
}

    ' TODO: should use some conversion from textureCopy.Description.Format
    Dim bitmap = New Bitmap(factory, textureCopy.Description.Width, textureCopy.Description.Height, PixelFormatFromFormat(textureCopy.Description.Format), dataRectangle)

    Using WICStream = New WICStream(factory, _filename, IO.NativeFileAccess.ReadWrite)
        Dim bitmapEncoder As DdsEncoder = New DdsEncoder(WICStream.NativePointer)

        If bitmapEncoder IsNot Nothing Then
            Using bitmapFrameEncode = New BitmapFrameEncode(bitmapEncoder)
                bitmapFrameEncode.Initialize()
                bitmapFrameEncode.SetSize(bitmap.Size.Width, bitmap.Size.Height)

                bitmapFrameEncode.SetPixelFormat(PixelFormatFromFormat(textureCopy.Description.Format))
                bitmapFrameEncode.WriteSource(bitmap)
                bitmapFrameEncode.Commit()
                bitmapEncoder.CreateNewFrame(bitmapFrameEncode, 0, 0, 0)
            End Using
            bitmapEncoder.Dispose()
        End If


    End Using

    _device.UnmapSubresource(textureCopy, 0)
    textureCopy.Dispose()
    bitmap.Dispose()
    factory.Dispose()
    factory = Nothing
    bitmap = Nothing
    textureCopy = Nothing
End Sub

  Public Function PixelFormatFromFormat(format As SharpDX.DXGI.Format) As Guid
    Select Case format
        Case SharpDX.DXGI.Format.R32G32B32A32_Typeless, SharpDX.DXGI.Format.R32G32B32A32_Float
            Return SharpDX.WIC.PixelFormat.Format128bppRGBAFloat
        Case SharpDX.DXGI.Format.R32G32B32A32_UInt, SharpDX.DXGI.Format.R32G32B32A32_SInt
            Return SharpDX.WIC.PixelFormat.Format128bppRGBAFixedPoint
        Case SharpDX.DXGI.Format.R32G32B32_Typeless, SharpDX.DXGI.Format.R32G32B32_Float
            Return SharpDX.WIC.PixelFormat.Format96bppRGBFloat
        Case SharpDX.DXGI.Format.R32G32B32_UInt, SharpDX.DXGI.Format.R32G32B32_SInt
            Return SharpDX.WIC.PixelFormat.Format96bppRGBFixedPoint
        Case SharpDX.DXGI.Format.R16G16B16A16_Typeless, SharpDX.DXGI.Format.R16G16B16A16_Float, SharpDX.DXGI.Format.R16G16B16A16_UNorm, SharpDX.DXGI.Format.R16G16B16A16_UInt, SharpDX.DXGI.Format.R16G16B16A16_SNorm, SharpDX.DXGI.Format.R16G16B16A16_SInt
            Return SharpDX.WIC.PixelFormat.Format64bppRGBA
        Case SharpDX.DXGI.Format.R32G32_Typeless, SharpDX.DXGI.Format.R32G32_Float, SharpDX.DXGI.Format.R32G32_UInt, SharpDX.DXGI.Format.R32G32_SInt, SharpDX.DXGI.Format.R32G8X24_Typeless, SharpDX.DXGI.Format.D32_Float_S8X24_UInt,
            SharpDX.DXGI.Format.R32_Float_X8X24_Typeless, SharpDX.DXGI.Format.X32_Typeless_G8X24_UInt
            Return Guid.Empty
        Case SharpDX.DXGI.Format.R10G10B10A2_Typeless, SharpDX.DXGI.Format.R10G10B10A2_UNorm, SharpDX.DXGI.Format.R10G10B10A2_UInt
            Return SharpDX.WIC.PixelFormat.Format32bppRGBA1010102
        Case SharpDX.DXGI.Format.R11G11B10_Float
            Return Guid.Empty
        Case SharpDX.DXGI.Format.R8G8B8A8_Typeless, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.Format.R8G8B8A8_UNorm_SRgb, SharpDX.DXGI.Format.R8G8B8A8_UInt, SharpDX.DXGI.Format.R8G8B8A8_SNorm, SharpDX.DXGI.Format.R8G8B8A8_SInt
            Return SharpDX.WIC.PixelFormat.Format32bppRGBA
        Case SharpDX.DXGI.Format.R16G16_Typeless, SharpDX.DXGI.Format.R16G16_Float, SharpDX.DXGI.Format.R16G16_UNorm, SharpDX.DXGI.Format.R16G16_UInt, SharpDX.DXGI.Format.R16G16_SNorm, SharpDX.DXGI.Format.R16G16_SInt
            Return Guid.Empty
        Case SharpDX.DXGI.Format.R32_Typeless, SharpDX.DXGI.Format.D32_Float, SharpDX.DXGI.Format.R32_Float, SharpDX.DXGI.Format.R32_UInt, SharpDX.DXGI.Format.R32_SInt
            Return Guid.Empty
        Case SharpDX.DXGI.Format.R24G8_Typeless, SharpDX.DXGI.Format.D24_UNorm_S8_UInt, SharpDX.DXGI.Format.R24_UNorm_X8_Typeless
            Return SharpDX.WIC.PixelFormat.Format32bppGrayFloat
        Case SharpDX.DXGI.Format.X24_Typeless_G8_UInt, SharpDX.DXGI.Format.R9G9B9E5_Sharedexp, SharpDX.DXGI.Format.R8G8_B8G8_UNorm, SharpDX.DXGI.Format.G8R8_G8B8_UNorm
            Return Guid.Empty
        Case SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.DXGI.Format.B8G8R8X8_UNorm
            Return SharpDX.WIC.PixelFormat.Format32bppBGRA
        Case SharpDX.DXGI.Format.R10G10B10_Xr_Bias_A2_UNorm
            Return SharpDX.WIC.PixelFormat.Format32bppBGR101010
        Case SharpDX.DXGI.Format.B8G8R8A8_Typeless, SharpDX.DXGI.Format.B8G8R8A8_UNorm_SRgb, SharpDX.DXGI.Format.B8G8R8X8_Typeless, SharpDX.DXGI.Format.B8G8R8X8_UNorm_SRgb
            Return SharpDX.WIC.PixelFormat.Format32bppBGRA
        Case SharpDX.DXGI.Format.R8G8_Typeless, SharpDX.DXGI.Format.R8G8_UNorm, SharpDX.DXGI.Format.R8G8_UInt, SharpDX.DXGI.Format.R8G8_SNorm, SharpDX.DXGI.Format.R8G8_SInt
            Return Guid.Empty
        Case SharpDX.DXGI.Format.R16_Typeless, SharpDX.DXGI.Format.R16_Float, SharpDX.DXGI.Format.D16_UNorm, SharpDX.DXGI.Format.R16_UNorm, SharpDX.DXGI.Format.R16_SNorm
            Return SharpDX.WIC.PixelFormat.Format16bppGrayHalf
        Case SharpDX.DXGI.Format.R16_UInt, SharpDX.DXGI.Format.R16_SInt
            Return SharpDX.WIC.PixelFormat.Format16bppGrayFixedPoint
        Case SharpDX.DXGI.Format.B5G6R5_UNorm
            Return SharpDX.WIC.PixelFormat.Format16bppBGR565
        Case SharpDX.DXGI.Format.B5G5R5A1_UNorm
            Return SharpDX.WIC.PixelFormat.Format16bppBGRA5551
        Case SharpDX.DXGI.Format.B4G4R4A4_UNorm
            Return Guid.Empty

        Case SharpDX.DXGI.Format.R8_Typeless, SharpDX.DXGI.Format.R8_UNorm, SharpDX.DXGI.Format.R8_UInt, SharpDX.DXGI.Format.R8_SNorm, SharpDX.DXGI.Format.R8_SInt
            Return SharpDX.WIC.PixelFormat.Format8bppGray
        Case SharpDX.DXGI.Format.A8_UNorm
            Return SharpDX.WIC.PixelFormat.Format8bppAlpha
        Case SharpDX.DXGI.Format.R1_UNorm
            Return SharpDX.WIC.PixelFormat.Format1bppIndexed
        Case Else

            Return Guid.Empty
    End Select
End Function

WIC Codec Info Page

\$\endgroup\$
10
  • \$\begingroup\$ I need to return the image as a "System.Drawing.Image." I'm not able to save the image, it must stay in memory. So I need to get from the SharpDX Bitmap to Image. \$\endgroup\$
    – Reaper
    Commented Jan 19, 2017 at 1:07
  • \$\begingroup\$ rather than use a file stream change it to a memory stream and the call image.fromstream. Ill update my answer if you need \$\endgroup\$ Commented Jan 19, 2017 at 5:31
  • \$\begingroup\$ Updated my answer only thing is I'm not sure if a system.drawing.image can load a .DDS file so you will need to play with the texture saving methods.... I'm going over my code now so I should have a bit more of a working in code solution soon'ish. \$\endgroup\$ Commented Jan 19, 2017 at 5:46
  • \$\begingroup\$ Now that I've added this to production. It is not fast enough. Is there a faster method? \$\endgroup\$
    – Reaper
    Commented Apr 27, 2017 at 18:12
  • \$\begingroup\$ You could write your own importer and exporter. Take a look at DevIL its an image lib that may help. Ill have a tinker after school and see what I can come up with. Can I ask how slow? in say milliseconds? Because there may not be a faster way to do it in DotNet. System.Drawing.Image is not really meant for this kind of thing so that would most likely be the problem. \$\endgroup\$ Commented Apr 27, 2017 at 20:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .