Как взаимодействовать с изображением, отрытым в IWICFormatConverter?
Я пишу приложение для обработки изображений (Преимущественно dds формата) на .NET Core. Для декодирования форматов я с пользую wincodecs, полученный результат конвертирую в HBTIMAP для дальнейшего вывода изображение в PictureBox. Изображение без проблем выводится, однако при попытке начать с ним работать - программа сообщает об ошибке доступа, поскольку оно уже используется в классе отвечающем за декодирование форматов.
Часть заголовочного документа с интерфейсом, в котором я этим пользуюсь:
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)
{
...
IMGReader IWICReader((HplMaterial.getFileDirectory() + HplMaterial.getDiffuse()).c_str());
pictureBox1->Image = pictureBox1->Image->FromHbitmap((IntPtr)IWICReader.IWICBitmapToHBITMAP());
HplMaterial.setResolution(IWICReader.getBitmapHeight(), IWICReader.getBitmapWidth());
...
}
}
catch (const std::exception& ex)
{
MessageBox::Show(StdToSys(ex.what()), "Error", MessageBoxButtons::OK, MessageBoxIcon::Error);
}
}
Заголовочный файл читающего класса:
#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;
BOOLEAN pathExist(LPCWSTR path);
IMGReader() {};
public:
IMGReader(LPCWSTR path) { load(path); };
~IMGReader() { wConverter->Release(); };
void load(LPCWSTR path);
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
UINT getBitmapHeight() { return BitHeight; };
UINT getBitmapWidth() { return BitWidth; };
HBITMAP IWICBitmapToHBITMAP();
};
Имплементационный файл класса:
#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;
}
Существует ли какой-то аналог Image->Clone() для подобного подхода? Так же было замечено, что рри удалении IWIC элементов через Release() в методе load(), в PictureBox изображение не выводится. Спасибо.
Ответы (1 шт):
Итак, я решил проблему. Проблема оказалась довольно банальной - я не хранил данные об изображении, каждый раз создавая новые методы IWIC из-за чего прошлые просто уходили в память. Всё заработало, как только перенёс их в класс.
Заголовочный:
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();
};
Имплементационный:
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);
}