locked
Interoperability between WinRT and COM: IStream

    Question

  • I have a function that uses WIC to load and manipulate an image. Before, I used IWICImagingFactory::CreateDecoderFromFilename but since WinRT restricts this to the application package directory, an alternative solution is required.

    I've seen one post where the solution was to copy the file to the temporary folder, but this causes disk I/O which consumes power and seems like a very superfluous operation given the fact that I have an IStorageFile interface and can use FileIO::ReadBufferAsync to receive an IBuffer object.

    The question is: how to pass this IBuffer object to the WIC which expects an IStream. Is there any way to create an IStream object from DataReader, the WinRT IInputStream or maybe get an HGLOBAL from the file buffer without allocating and copying the whole memory block?

    I don't want to jump through so many hoops when I already have the buffered data in memory and just want to create a WIC image from it.


    Tuesday, April 10, 2012 2:40 PM

Answers

  • In the end, the only viable solution was to copy all data from the IBuffer to a newly created IStream interface like so:

    IStream* createIStreamFromIBuffer(Streams::IBuffer ^buffer) {
        // convert the IBuffer into an IStream to be used with WIC
        IStream *fileContentsStream;
        HRESULT res = CreateStreamOnHGlobal(NULL, TRUE, &fileContentsStream);
        if (FAILED(res) || !fileContentsStream) {
            throw ref new FailureException();
        }
        Streams::DataReader^ dataReader = Streams::DataReader::FromBuffer(buffer);
        // read the data into the stream in chunks of 1MB to preserve memory
        while (dataReader->UnconsumedBufferLength > 0) {
            UINT chunkSize = min(1024*1024, dataReader->UnconsumedBufferLength);
            auto data = ref new Platform::Array<uint8>(chunkSize);
            dataReader->ReadBytes(data);
            ULONG written;
            res = fileContentsStream->Write(data->Data, chunkSize, &written);
            if (FAILED(res) || written != chunkSize) {
                fileContentsStream->Release();
                throw ref new FailureException();
            }
        }
        return fileContentsStream;
    }
    Sure it's not the best way, but it works...


    • Edited by Marcus Ilgner Thursday, April 12, 2012 12:45 PM
    • Marked as answer by Jesse Jiang Wednesday, April 25, 2012 6:57 AM
    Thursday, April 12, 2012 12:45 PM

All replies

  • Try to use byte* to convert them

    NEU_ShieldEdge

    Wednesday, April 11, 2012 11:06 AM
  • In the end, the only viable solution was to copy all data from the IBuffer to a newly created IStream interface like so:

    IStream* createIStreamFromIBuffer(Streams::IBuffer ^buffer) {
        // convert the IBuffer into an IStream to be used with WIC
        IStream *fileContentsStream;
        HRESULT res = CreateStreamOnHGlobal(NULL, TRUE, &fileContentsStream);
        if (FAILED(res) || !fileContentsStream) {
            throw ref new FailureException();
        }
        Streams::DataReader^ dataReader = Streams::DataReader::FromBuffer(buffer);
        // read the data into the stream in chunks of 1MB to preserve memory
        while (dataReader->UnconsumedBufferLength > 0) {
            UINT chunkSize = min(1024*1024, dataReader->UnconsumedBufferLength);
            auto data = ref new Platform::Array<uint8>(chunkSize);
            dataReader->ReadBytes(data);
            ULONG written;
            res = fileContentsStream->Write(data->Data, chunkSize, &written);
            if (FAILED(res) || written != chunkSize) {
                fileContentsStream->Release();
                throw ref new FailureException();
            }
        }
        return fileContentsStream;
    }
    Sure it's not the best way, but it works...


    • Edited by Marcus Ilgner Thursday, April 12, 2012 12:45 PM
    • Marked as answer by Jesse Jiang Wednesday, April 25, 2012 6:57 AM
    Thursday, April 12, 2012 12:45 PM
  • How about using this from shcore.h:

        auto randomAccessStream = ref new Windows::Storage::Streams::InMemoryRandomAccessStream();
        CheckHResult(CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(stream)));

     

    Saturday, June 01, 2013 10:12 PM