Search code examples
c++imageimage-processingstdoutwic

How to write an image to STDOUT with Wincodec.h (WIC)


I came across this example and couldn't figure out how to change stream->InitializeFromFilename to something that outputs to STDOUT, inside the HRESULT SavePixelsToFile32bppPBGRA(UINT width, UINT height, UINT stride, LPBYTE pixels, LPWSTR filePath, const GUID &format) function. Tried using stream->InitializeFromMemory but hit a wall due to minimal C++ experience.

Reasons behind this is that i'm building something and would like to pipe the stdout of the example using something else.


Solution

  • Thanks to @SimonMourier, I was able to update his code to achieve what was needed.

    SavePixelsToFile32bppPBGRA now writes the data to an IStream pointer, streamOut. It also invokes a new function at the end, to output data.

    HRESULT SavePixelsToFile32bppPBGRA(UINT width, UINT height, UINT stride, LPBYTE pixels, const GUID& format)
    {
        if (!pixels)
            return E_INVALIDARG;
    
        HRESULT hr = S_OK;
        IWICImagingFactory* factory = nullptr;
        IWICBitmapEncoder* encoder = nullptr;
        IWICBitmapFrameEncode* frame = nullptr;
        IWICStream* streamOut = nullptr;
        IStream * streamIn = nullptr;
        GUID pf = GUID_WICPixelFormat32bppPBGRA;
        BOOL coInit = CoInitialize(nullptr);
    
        HRCHECK(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)));
        HRCHECK(factory->CreateStream(&streamOut));
        HRCHECK(CreateStreamOnHGlobal(NULL, true, &streamIn));
        HRCHECK(streamOut->InitializeFromIStream(streamIn));
        HRCHECK(factory->CreateEncoder(format, nullptr, &encoder));
        HRCHECK(encoder->Initialize(streamOut, WICBitmapEncoderNoCache));
        HRCHECK(encoder->CreateNewFrame(&frame, nullptr)); // we don't use options here
        HRCHECK(frame->Initialize(nullptr)); // we dont' use any options here
        HRCHECK(frame->SetSize(width, height));
        HRCHECK(frame->SetPixelFormat(&pf));
        HRCHECK(frame->WritePixels(height, stride, stride * height, pixels));
        HRCHECK(frame->Commit());
        HRCHECK(encoder->Commit());
    
        sendIStreamToOutput(streamOut);
    
    cleanup:
        RELEASE(streamIn);
        RELEASE(streamOut);
        RELEASE(frame);
        RELEASE(encoder);
        RELEASE(factory);
        if (coInit) CoUninitialize();
        return hr;
    }
    

    sendIStreamToOutput reads the data from the IStream and writes it to std::cout (with binary mode active).

    void sendIStreamToOutput (IStream * pIStream) {
    
        STATSTG sts;
        pIStream->Stat(&sts, STATFLAG_DEFAULT);
        ULARGE_INTEGER uli = sts.cbSize;
        LARGE_INTEGER zero;
        zero.QuadPart = 0;
        ULONG size = (ULONG)uli.QuadPart;
        char* bits = new char[size];
        ULONG written;
        pIStream->Seek(zero, STREAM_SEEK_SET, NULL);
        pIStream->Read(bits, size, &written);
        
        std::ostream& lhs = std::cout;
    
        _setmode(_fileno(stdout), _O_BINARY);
    
        lhs.write(bits, size);
    
        fflush(stdout);
    
        delete[] bits;
     }