Nikita
Nikita

Reputation: 11

How can I access the image opened in the IWICBitmap Decoder?

I am making a .NET application for image editing. To show an image in a PictureBox, I open it with IWIC to translate to HBITMAP and then paste it into the PictureBox using the FromHbitmap method. This means that while the Image instance exists in the application, I cannot work with it. So how can I change my reader class to get access to image?

IMGReader.h

#pragma once

#include <wincodec.h> // WIC codec header for decoding image from file

#include "StringConverter.h"

#pragma comment (lib, "windowscodecs")

class IMGReader
{
    IWICFormatConverter* wConverter;

    UINT BitHeight;
    UINT BitWidth;

    IMGReader() {};
    
    BOOLEAN pathExist(LPCWSTR path);
public:
    IMGReader(LPCWSTR path) { load(path); };
    ~IMGReader() { wConverter->Release(); };

    void load(LPCWSTR path);

    UINT getBitmapHeight()  { return BitHeight; };
    UINT getBitmapWidth()   { return BitWidth; };

    HBITMAP IWICBitmapToHBITMAP();
};

IMGReader.cpp

#include "IMGReader.h"
#include "MTTErrorLogger.h"

#include <filesystem>
#include <vector>

void IMGReader::load(LPCWSTR path)
{
    HRESULT hr;     // For checking errors

    if (!pathExist(path)) { path = L"nodata.jpg"; }; // Check if image really exist in this derectory

    // Craete WIC factory
    IWICImagingFactory* wicFactory = NULL;
    hr = CoCreateInstance(
        CLSID_WICImagingFactory,    // CLS ID of the object making
        NULL,                       // Not part of agregate 
        CLSCTX_INPROC_SERVER,       // DLL runs in the same process
        IID_IWICImagingFactory,     // Ref to interface that communicates with the object
        (LPVOID*)&wicFactory        // The pointer that'll contain factory
    );

    // Create decoder
    IWICBitmapDecoder* wicDecoder = NULL;
    hr = wicFactory->CreateDecoderFromFilename(
        path,                           // Path to reading file
        NULL,                           // No preferred vendor
        GENERIC_READ,                   // Reading file
        WICDecodeMetadataCacheOnLoad,   // Cache on load 
        &wicDecoder                     // Making decoder
    );

    // Read frame from the image
    IWICBitmapFrameDecode* wicFrame = NULL;
    hr = wicDecoder->GetFrame(0, &wicFrame);

    //Create converter
    IWICFormatConverter* wicConverter = NULL;
    hr = wicFactory->CreateFormatConverter(&wicConverter);

    // Setup the converter
    hr = wicConverter->Initialize(
        wicFrame,                       // Frame
        GUID_WICPixelFormat32bppPBGRA,  // Pixel format
        WICBitmapDitherTypeNone,        // Irrelevant
        NULL,                           // No palette needed, irrelevant
        0.0,                            // Alpha transparency % irrelevant
        WICBitmapPaletteTypeCustom      // Irrelevant
    );

    wicConverter->GetSize(&BitHeight, &BitWidth);

    wConverter = wicConverter;
}

HBITMAP IMGReader::IWICBitmapToHBITMAP()
{
    UINT height = BitHeight;    // Bitmap height
    UINT width  = BitWidth;     // Bitmap width
    wConverter->GetSize(&width, &height);

    std::vector<BYTE> buffer(width * height * 4);
    wConverter->CopyPixels(0, width * 4, buffer.size(), buffer.data());

    HBITMAP bitmap = CreateBitmap(width, height, 1, 32, buffer.data()); // Create bitmap from IWICBitmap data

    return bitmap;
}

BOOLEAN IMGReader::pathExist(LPCWSTR path)
{
    if (std::filesystem::exists(path)) {
        return true;
    }
    return false;
}

Using in main form:

private: System::Void newToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {
    try
    {
        OpenFileDialog^ ofd = gcnew OpenFileDialog();
        ofd->Filter = "HPL Materials(*.mat)|*.mat";
        if (ofd->ShowDialog() == System::Windows::Forms::DialogResult::OK)
        {
            String^ path = gcnew String(ofd->FileName);
            std::wstring directory = SystemToWide(System::IO::Path::GetDirectoryName(path) + "\\"); 
            HplMaterial.setFileDirectory(directory);

            HplMaterial.setMaterialPath(SystemToWide(path));
            HPLMatReader::read(HplMaterial, SystemToWide(path));
            textBox1->Text = WideToSystem(HplMaterial.getDiffuse());
            textBox2->Text = WideToSystem(HplMaterial.getNMap());
            textBox3->Text = WideToSystem(HplMaterial.getSpecular());
            textBox4->Text = WideToSystem(HplMaterial.getHeight());
            textBox5->Text = WideToSystem(HplMaterial.getAlpha());
            textBox6->Text = WideToSystem(HplMaterial.getIllumination());
            textBox7->Text = WideToSystem(HplMaterial.getMaterialPath());
            textBox8->Text = WideToSystem(HplMaterial.getFileDirectory() + HplMaterial.getDiffuse());

            IMGReader IWICReader((HplMaterial.getFileDirectory() + HplMaterial.getDiffuse()).c_str());
            pictureBox1->Image = pictureBox1->Image->FromHbitmap((IntPtr)IWICReader.IWICBitmapToHBITMAP());
            HplMaterial.setResolution(IWICReader.getBitmapHeight(), IWICReader.getBitmapWidth());

            label9->Text = WideToSystem(HplMaterial.getMaterialRes());
            label7->Text = WideToSystem(HplMaterial.getPhysMaterial());
        }
    }
    catch (const std::exception& ex)
    {
        MessageBox::Show(StdToSys(ex.what()), "Error", MessageBoxButtons::OK, MessageBoxIcon::Error);
    }
}

Thank you.

Upvotes: 0

Views: 464

Answers (1)

Nikita
Nikita

Reputation: 11

So I solved the problem. The problem seems to be that I didn’t store the image data in a specific location, but created new ones each time in the load method. I made following modifications in code:

Header:

#pragma once

#include <wincodec.h> // WIC codec header for decoding image from file
#include <atlcomcli.h>

    #include "StringConverter.h"
    
    #pragma comment (lib, "windowscodecs")
    
    class IMGReader
    {
        CComPtr<IWICImagingFactory>     m_pImagingFactory;
        CComPtr<IWICBitmapDecoder>      m_pBitmapDecoder;
        CComPtr<IWICBitmapFrameDecode>  m_pFrameDecoder;
        CComPtr<IWICFormatConverter>    m_pConverter;
    
        UINT BitHeight;
        UINT BitWidth;
    
        BOOLEAN pathExist(LPCWSTR path);
    
        IMGReader() {};
    public:
        IMGReader(LPCWSTR path) { load(path); };
        ~IMGReader() { SafeRelease(&m_pConverter); };
    
        void load(LPCWSTR path);
        void clean();
        template <class T> void SafeRelease(T** ppT)
        {
            if (*ppT)
            {
                (*ppT)->Release();
                *ppT = NULL;
            }
        }
    
        UINT getBitmapHeight()  { return BitHeight; };
        UINT getBitmapWidth()   { return BitWidth; };
    
        HBITMAP IWICBitmapToHBITMAP();
    };

Implementation:

void IMGReader::load(LPCWSTR path)
{
    HRESULT hr;

    m_pImagingFactory   = NULL;
    m_pBitmapDecoder    = NULL;
    m_pFrameDecoder     = NULL;
    m_pConverter        = NULL;

    hr = CoCreateInstance(
        CLSID_WICImagingFactory,    // CLS ID of the object making
        NULL,                       // Not part of agregate 
        CLSCTX_INPROC_SERVER,       // DLL runs in the same process
        IID_IWICImagingFactory,     // Ref to interface that communicates with the object
        (LPVOID*)&m_pImagingFactory // The pointer that'll contain factory
    );

    hr = m_pImagingFactory->CreateDecoderFromFilename(
        path,                           // Path to reading file
        NULL,                           // No preferred vendor
        GENERIC_READ,                   // Reading file
        WICDecodeMetadataCacheOnLoad,   // Cache on load 
        &m_pBitmapDecoder               // Making decoder
    );

    hr = m_pBitmapDecoder->GetFrame(0, &m_pFrameDecoder);

    hr = m_pImagingFactory->CreateFormatConverter(&m_pConverter);

    hr = m_pConverter->Initialize(
        m_pFrameDecoder,                // Frame
        GUID_WICPixelFormat32bppPBGRA,  // Pixel format
        WICBitmapDitherTypeNone,        // Irrelevant
        NULL,                           // No palette needed, irrelevant
        0.0,                            // Alpha transparency % irrelevant
        WICBitmapPaletteTypeCustom      // Irrelevant
    );

    this->m_pConverter->GetSize(&BitHeight, &BitWidth);
}

Upvotes: 0

Related Questions