如何访问在 IWICBitmap 解码器中打开的图像?
How can I access the image opened in the IWICBitmap Decoder?
我正在制作一个用于图像编辑的 .NET 应用程序。为了在 PictureBox 中显示图像,我使用 IWIC 打开它以转换为 HBITMAP,然后使用 FromHbitmap 方法将其粘贴到 PictureBox 中。这意味着虽然 Image 实例存在于应用程序中,但我无法使用它。那么如何更改 reader class 以访问图像?
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;
}
在主窗体中使用:
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);
}
}
谢谢。
所以我解决了这个问题。问题似乎是我没有将图像数据存储在特定位置,而是在加载方法中每次都创建新的。我在代码中做了以下修改:
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();
};
实施:
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);
}
我正在制作一个用于图像编辑的 .NET 应用程序。为了在 PictureBox 中显示图像,我使用 IWIC 打开它以转换为 HBITMAP,然后使用 FromHbitmap 方法将其粘贴到 PictureBox 中。这意味着虽然 Image 实例存在于应用程序中,但我无法使用它。那么如何更改 reader class 以访问图像?
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;
}
在主窗体中使用:
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);
}
}
谢谢。
所以我解决了这个问题。问题似乎是我没有将图像数据存储在特定位置,而是在加载方法中每次都创建新的。我在代码中做了以下修改:
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();
};
实施:
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);
}