The answer above is the correct way to do it, there is ABSOLUTELY no need to create the 50 line if statement. I must admit that is what I did first, but what if you get a new format? You wont have an answer. Doing it this way will always work.
Thanks to whoever posted this answer above for the solution, but the pseudo code calculates the stride a bit wrongly. The stride is essentially the number of Bytes required to encode all the bits. So if you have less than 8 bits left over, you need to get 1 more byte to manage them.
Here is the answer in C++, mostly copied from the WIC documentation. This documentation is excellent, but as pointed out there is no example of how to get an instance of the IWICPixelFormatInfo. That is the part that I couldn't get.
Getting BitsPerPixel and Stride:
First: get a IWICBitmapFrameDecode as the Bitmap source
// 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);
}
Next get the pixel format and the 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);
}
You have two choices:
//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
//////////////////////////////////////////////////////////////////////////////////
Or, if you want to use the image, you can create it...
// 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
/////////////////////////////////////////////////////////////////////////////////
Dont forget to tidy up...
SafeRelease(&pILock);
...
UPDATE: 2020. For Thomas.
I actually was writing Delphi code when I answer this so I was translating back to c++ :
Given this Pascal header:
function CreateComponentInfo(const clsidComponent: TGUID;
out ppIInfo: IWICComponentInfo): HRESULT; stdcall;
Probably translates to:
HRESULT CreateComponentInfo(pGUID *clsidComponent, pIWICComponentInfo *ppIInfo);
I suspect either I have not referenced the pointer correctly in the example above.
Here is the working Delphi Code (object 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;
So the call can take a GUID (if you get the pointer right)
Anyway, a few 'if' statements is the path I am taking, since there is only a subset that I know are going to be dealt with.