2

我认为这个主题说明了一切。但在某些细节上,我正在加载、操作、然后显示位图,并在 GDI 中进行。现在我想增加一些速度,因为它反复发生。

许多年前,我将 DirectX 用于其他事情,但我所看到的一切都说要离开 DirectX,转而使用 Direct2D。所以是时候扔掉所有的知识,重新开始了。真正的 MS 方式 ;-)

好吧,为了操作位图,在它进入渲染之前,我看到我可以使用“Lock()”来获取它。界面上的一个功能也会告诉我尺寸。但我也需要知道 BBP,并大步前进。

在有人说“你为什么不使用 ::GetBBP()... DUH”之前,经过数小时搜索 MSDN 和其他来源后,我一直无法远程找到类似的东西。并且有很多非常令人困惑的 COM 接口。

我唯一能找到的是 GetPixelFormat(),它返回一个 GUID,然后我可以编写大约 150 个“if (...)”语句来比较它。就这样我可以测试它的三个值,如果它们都不是(1,8,32)则拒绝它,这几乎不是处理这个问题的有效方法。

GetPixelFormat() 也没有告诉我步幅。

有没有办法做到这一点?

(位图也是未压缩的,所以我什至不需要通过 IWICBitmapDecoder 运行它们,但我还没有解释如何简单地告诉 IWICBitmap “这是一个 blob,将它用作大小 xy 的位图”)

感谢您的任何帮助。

-斯科特

4

2 回答 2

3

使用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;
于 2015-12-17T18:15:36.193 回答
3

上面的答案是正确的方法,绝对不需要创建 50 行 if 语句。我必须承认这是我首先做的,但如果你得到一个新格式怎么办?你不会有答案的。这样做总是有效的。

感谢上面为解决方案发布此答案的人,但伪代码计算步幅有点错误。步幅本质上是编码所有位所需的字节数。因此,如果剩余的位少于 8 位,则需要多获得 1 个字节来管理它们。

这是 C++ 中的答案,主要是从 WIC 文档中复制的。该文档非常好,但正如所指出的,没有关于如何获取 IWICPixelFormatInfo 实例的示例。那是我无法得到的部分。

获取 BitsPerPixel 和 Stride:

第一:获取一个 IWICBitmapFrameDecode 作为 Bitmap 源

// 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);

我怀疑在上面的示例中我没有正确引用指针。

这是工作的德尔福代码(对象帕斯卡)

// 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(如果你得到正确的指针)

于 2018-10-07T03:23:30.857 回答