deng0 / DirectXTexNet

A .NET wrapper for the DirectXTex library.
Other
25 stars 11 forks source link

ScratchImage.SaveToJPGMemory throws System.Runtime.InteropServices.COMException: 'The request is not supported. (0x80070032)' #8

Closed softinitializing closed 9 months ago

softinitializing commented 9 months ago

I am trying to load a dds file into wpf image control i found there is a method SaveToJPGMemory so i tried to use it to convert to the ScratchImage to a ImageSource but it throws this Exception, i dont really know what to put as arguments i want to display the image it self not any mipmap with full quality so i put 0 for index and 100f for quality , not sure if this is correct ?

Screenshot 2024-02-01 171838

public static ImageSource LoadDdsPreview(string path)
  {
      // Load image with DirectXTex.
      using (var image = TexHelper.Instance.LoadFromDDSFile(path, DDS_FLAGS.NONE))
      {
          var y = image.ComputeImageIndex(0,0,0);
          using var jpg = image.SaveToJPGMemory(0, 100f);
          return ConvertJpgStreamToImageSource(jpg);
      }
  }

  public static BitmapImage ConvertJpgStreamToImageSource(UnmanagedMemoryStream jpgStream)
  {
      // Read the JPEG data from the stream
      byte[] jpgData = new byte[jpgStream.Length];
      jpgStream.Read(jpgData, 0, jpgData.Length);

      // Create a MemoryStream from the JPEG data
      using (MemoryStream memoryStream = new MemoryStream(jpgData))
      {
          // Create a BitmapImage and set the stream source
          BitmapImage imageSource = new BitmapImage();
          imageSource.BeginInit();
          imageSource.CacheOption = BitmapCacheOption.OnLoad; // Load the image immediately
          imageSource.StreamSource = memoryStream;
          imageSource.EndInit();
          imageSource.Freeze(); // Freeze the image to prevent further modifications
          return imageSource;
      }
  }
deng0 commented 9 months ago

the quality option in SaveToJPGMemory needs to be set in the range of 0-1. In addition if the dds uses a compressed pixel format (e.g. BC1) you need to decompress it before you can convert it to jpg.

Try changing your first method to the following:

    public static ImageSource LoadDdsPreview(string path)
    {
        // Load image with DirectXTex.
        using (var image = TexHelper.Instance.LoadFromDDSFile(path, DDS_FLAGS.NONE))
        {
            var index = image.ComputeImageIndex(0, 0, 0);
            ScratchImage imageToUse = image;

            var im = image.GetImage(index);
            bool isCompressed = TexHelper.Instance.IsCompressed(im.Format);
            using var uncompressed = isCompressed ? image.Decompress(index, DXGI_FORMAT.UNKNOWN) : null;

            if (isCompressed)
            {
                imageToUse = uncompressed;
                index = uncompressed.ComputeImageIndex(0, 0, 0);
            }

            using var jpg = imageToUse.SaveToJPGMemory(index, 1f);
            return ConvertJpgStreamToImageSource(jpg);
        }
    }
softinitializing commented 9 months ago

wow thanks that's really working really fine and fast as well , thanks

twolast qustion if would allow me the method you provided doesnt seem to support alpha channel ?

How to convert png/jpg to dds (compressed with mipmaps ) ? all i found related is the Initialize2D method but i dont know what to do next

        public static byte[] ConvertToDds(string path)
        {
            DXGI_FORMAT Format = DXGI_FORMAT.BC7_UNORM_SRGB;
            int width = 1024;
            int height = 1024;
            int arrysize = 1;
            int miplevels = 12;
            CP_FLAGS fLAGS = CP_FLAGS.NONE;
            // Load image with DirectXTex.
            using (var image = TexHelper.Instance.Initialize2D(Format,width,height,arrysize,miplevels,fLAGS))
            {

                var y = image.GetMetadata();
                var pixels = image.GetPixels();
                // Assuming 'pixels' is the IntPtr pointing to the unmanaged memory and 'size' is the size of the data in bytes

                int size = (int)image.GetPixelsSize();
                byte[] managedArray = new byte[size];

                // Copy the data from the unmanaged pointer to the byte array
                Marshal.Copy(pixels, managedArray, 0, size);
                var f = ConvertToFormat(y.Format);

                return managedArray;
            }
        }

sorry to bother you

deng0 commented 9 months ago

No problem, I'm glad I can help. As this library is just a thin wrapper for DirectXTex and does not contain any documentation, you should consult the official documentation here: https://github.com/microsoft/DirectXTex/wiki/DirectXTex

Regarding your questions: The JPG format itself does not support an alpha channel. You should probably switch to PNG if you want to keep transparencies.

For converting to compressed dds with mipmaps you can do something like this:

using var orig = TexHelper.Instance.LoadFromFile(srcImagePath);
using var withMips = orig.GenerateMipMaps(TEX_FILTER_FLAGS.LINEAR, 0);
using var compressed = withMips.Compress(DXGI_FORMAT.BC7_UNORM_SRGB, TEX_COMPRESS_FLAGS.PARALLEL | TEX_COMPRESS_FLAGS.BC7_QUICK, 0);
compressed.SaveToDDSFile(DDS_FLAGS.NONE, ddsPath); 
softinitializing commented 9 months ago

thanks i got it