我认为这个主题说明了一切。 但在一些细节上,我正在加载、操作、然后显示位图,并且是在 GDI 中完成的。 现在我想增加一些速度,因为它反复发生。
很多年前,我将 DirectX 用于其他用途,但我所看到的一切都表明要摆脱 DirectX,转向 Direct2D。 所以是时候扔掉所有这些知识并重新开始了。 真正的 MS 方式;-)
嗯,为了操作位图,在它进入渲染之前,我发现我可以使用“Lock()”来获取它。 界面上的功能也会告诉我尺寸。 但我还需要了解 BBP,并跨步。
在有人说“你为什么不使用 ::GetBBP()... DUH”之前,经过几个小时的 MSDN 和其他来源搜索后,我一直无法远程找到类似的东西。并且有很多非常令人困惑的 COM 接口。
我唯一能找到的是 GetPixelFormat(),它返回一个 GUID,然后我需要编写大约 150 个“if (...)”语句来比较它。 这样我就可以测试它的三个值,如果不是其中一个值则拒绝(1,8,32),这几乎不是处理这个问题的有效方法。
GetPixelFormat() 也不告诉我步幅。
有办法做到这一点吗?
(位图也是未压缩的,所以我什至不需要通过 IWICBitmapDecoder 运行它们,但我还没有弄清楚如何简单地告诉 IWICBitmap“这是一个 blob,去使用它作为大小 x-y 的位图”)
感谢您的帮助。
-斯科特
上面的答案是正确的方法,绝对不需要创建 50 行 if 语句。 我必须承认这是我首先做的,但是如果你得到一个新的格式怎么办? 你不会有答案。 这样做总是有效的。
感谢上面发布此答案的人提供的解决方案,但伪代码计算步幅有点错误。步长本质上是对所有位进行编码所需的字节数。因此,如果剩余的字节数少于 8 位,则需要再获取 1 个字节来管理它们。
这是 C++ 的答案,大部分是从 WIC 文档复制的。 该文档非常出色,但正如所指出的,没有如何获取 IWICPixelFormatInfo 实例的示例。 这是我无法得到的部分。
首先:获取 IWICBitmapFrameDecode 作为位图源
// Initialize COM.
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
IWICImagingFactory *piFactory = NULL;
IWICBitmapDecoder *piDecoder = NULL;
IWICBitmapFrameDecode *pIDecoderFrame = NULL;
GUID *pPixelFormat = NULL;
// Create the COM imaging factory.
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_WICImagingFactory,
NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&piFactory));
}
// Create the decoder.
if (SUCCEEDED(hr))
{
hr = piFactory->CreateDecoderFromFilename(L"test.tif", NULL, GENERIC_READ,
WICDecodeMetadataCacheOnDemand, //For JPEG lossless decoding/encoding.
&piDecoder);
}
// Retrieve the First frame from the image (tif might have more than 1)
if (SUCCEEDED(hr))
{
hr = pIDecoder->GetFrame(0, &pIDecoderFrame);
}
接下来获取像素格式和BitsPerPixel
//////////////////////////////////////////////////////////////////////////////////
//// IMPORTANT PART OF THE ANSWER
//////////////////////////////////////////////////////////////////////////////////
// Get the Pixel Format
IDecoderFrame.GetPixelFormat(&pPixelFormat);
// Now get a POINTER to an instance of the Pixel Format
IWICComponentInfo *pIComponentInfo = NULL;
if (SUCCEEDED(hr))
{
hr = piFactory->CreateComponentInfo(pPixelFormat, &pIComponentInfo);
}
// Get IWICPixelFormatInfo from IWICComponentInfo
IWICPixelFormatInfo *pIPixelFormatInfo;
hr = pIComponentInfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast<void**>(&pIPixelFormatInfo));
// Now get the Bits Per Pixel
UInt32 bitsPerPixel;
if (SUCCEEDED(hr))
{
hr = pIPixelFormatInfo.GetBitsPerPixel(&bitsPerPixel);
}
你有两个选择:
//Manually Calculate the Stride from the Bits Per Pixel.
UINT width;
UINT height;
if (SUCCEEDED(hr))
{
hr = IDecoderFrame.GetSize(&width, &height);
}
float totalPixels = bitsPerPixel * width + 7; // +7 forces to next byte if needed
UINT stride = totalPixels / 8;
// ... now do something with stride-You can stop here if you dont need the bitmap
//////////////////////////////////////////////////////////////////////////////////
或者,如果您想使用该图像,您可以创建它...
// Alternative is to get a lock, by you need to actually create the bitmap
// by calling CreateBitmapFromSource. IF you do want to create the bitmap,
// then by all means create one.
IWICBitmap *pIBitmap = NULL;
IWICBitmapLock *pILock = NULL;
WICRect rcLock = { 0, 0, width, height }; // from GetSize earlier
// Create the bitmap from the image frame.
if (SUCCEEDED(hr))
{
hr = m_pIWICFactory->CreateBitmapFromSource(
pIDecoderFrame, // Create a bitmap from the image frame
WICBitmapCacheOnDemand, // Cache metadata when needed
&pIBitmap); // Pointer to the bitmap
}
if (SUCCEEDED(hr))
{
hr = pIBitmap->Lock(&rcLock, WICBitmapLockWrite, &pILock);
}
// Now get the stride from the lock.
piLock.GetStride(&stride);
/// END OF ANSWER
/////////////////////////////////////////////////////////////////////////////////
别忘了收拾...
SafeRelease(&pILock);
...
更新:2020。托马斯。
当我回答这个问题时,我实际上正在编写 Delphi 代码,所以我正在翻译回 c++ :
给出这个 Pascal 标头:
function CreateComponentInfo(const clsidComponent: TGUID;
out ppIInfo: IWICComponentInfo): HRESULT; stdcall;
可能翻译为:
HRESULT CreateComponentInfo(pGUID *clsidComponent, pIWICComponentInfo *ppIInfo);
我怀疑我在上面的示例中没有正确引用指针。
这是工作的 Delphi 代码(对象 Pascal)
// from the already created frame interface
var lPixelFormat: TGUID;
iFrame.GetPixelFormat(lPixelFormat);
if WCIUnSuccessful(lImagingFactory.CreateComponentInfo(lPixelFormat,
iComponentInfo)) then
exit;
iPixelformatInfo := iComponentInfo as IWICPixelFormatInfo;
if WCIUnSuccessful(iPixelformatInfo.GetBitsPerPixel(result.BitsPerPixel))
then
exit;
因此该调用可以采用 GUID(如果您的指针正确)
使用
IWICPixelFormatInfo
。
可以通过
IWICImagingFactory.CreateComponentInfo()
方法获取该接口。
WICPixelFormatGUID
获得的 IWICBitmap.GetPixelFormat()
值。QueryInterface( __uuidof(IWICPixelFormatInfo))
接口指针上使用IWICComponentInfo
来获取IWICPixelFormatInfo
接口指针。IWICPixelFormatInfo
指针指向GetBitsPerPixel()
将其转换为每个像素的字节数,就完成了。
比获取读锁更复杂一些,但仍然是另一种选择。
//Get the PixelFormatInfo for the bitmap's particular format
CLSID pixelFormat = bitmapSource.GetPixelFormat();
IWicComponentInfo componentInfo = WicFactory.CreateComponent(pixelFormat);
IWICPixelFormatInfo info = componentInfo as IWICPixelFormatInfo;
//Get the number of bytes per pixel (e.g. 32bpp -> 4 bytes)
UInt32 bitsPerPixel = info.GetBitsPerPixel();
Int32 bytesPerPixel = bitsPerPixel / 8;
//Calculate the format's stride
UInt32 width;
UInt32 height;
bitmapSource.GetSize(out width, out height);
Int32 stride = width * bytesPerPixel;
您可以使用以下函数从
WICPixelFormatGUID
快速方式或慢速方式获取每像素的位数:
UINT PixelFormatGUID2Bpp(IWICImagingFactory* pIWICImagingFactory, WICPixelFormatGUID* pGUID)
{
const BYTE bpp_lut[64] = { 0,1,2,4,8,1,2,4,8,16,16,16,24,24,32,32,32,32,48,16,32,48,64,64,96,128,128,128,32,64,128,64,24,32,40,48,56,64,48,64,80,96,112,128,40,80,32,40,48,56,64,72,64,80,96,112,128,144,64,48,32,16,32,64 };
UINT bpp;
if (!pGUID)
return 0;
if ((*(ULONGLONG*)&pGUID->Data1 == 0x4bfe4e036fddc324) && (*(ULONGLONG*)&pGUID->Data4 << 8 == 0xc98d76773d85b100) && (pGUID->Data4[7] <= 0x3f)) //the common part of pixel format GUIDs
return bpp_lut[pGUID->Data4[7]]; //Get the answer quickly
else if (pIWICImagingFactory)
{
IWICComponentInfo* pPixelFormatInfo;
if (pIWICImagingFactory->CreateComponentInfo(*pGUID, &pPixelFormatInfo) >= 0)
{
IWICPixelFormatInfo* instPixelFormatInfo;
if (pPixelFormatInfo->QueryInterface(__uuidof(IWICPixelFormatInfo), (LPVOID*)(&instPixelFormatInfo)) >= 0)
{
if (instPixelFormatInfo->GetBitsPerPixel(&bpp) >= 0) // Get the answer slowly
return bpp;
}
}
}
return 0;
}