📄 bmpconv.cpp
字号:
/*++
Copyright (c) 2005 Microsoft Corporation
All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
File Name:
bmpconv.cpp
Abstract:
WIC bitmap conversion class implementation. This class provides a wrapper to a bitmap
stream that uses WIC to access bitmap data and provide conversion functionality.
--*/
#include "precomp.h"
#include "debug.h"
#include "globals.h"
#include "xdstring.h"
#include "xdexcept.h"
#include "bmpconv.h"
/*++
Routine Name:
CBmpConverter::CBmpConverter
Routine Description:
CBmpConverter default constructor
Arguments:
None
Return Value:
None
Throws an exception on error.
--*/
CBmpConverter::CBmpConverter() :
m_pImagingFactory(NULL),
m_pBitmap(NULL),
m_pColorContext(NULL),
m_pCurrentLock(NULL),
m_ePixelFormat(kWICPixelFormatDontCare)
{
//
// Make sure we have an imaging factory to work with
//
HRESULT hr = CreateImagingFactory();
if (FAILED(hr))
{
throw CXDException(hr);
}
}
/*++
Routine Name:
CBmpConverter::CBmpConverter
Routine Description:
CBmpConverter constructor
Arguments:
ePixFormat - Bitmap pixel format
cWidth - Bitmap width
cHeight - Bitmap height
dpiX - Bitmap horizontal resolution
dpiY - Bitmap vertical resolution
Return Value:
None
Throws an exception on error.
--*/
CBmpConverter::CBmpConverter(
__in CONST EWICPixelFormat& ePixFormat,
__in CONST UINT& cWidth,
__in CONST UINT& cHeight,
__in CONST DOUBLE& dpiX,
__in CONST DOUBLE& dpiY
) :
m_pImagingFactory(NULL),
m_pBitmap(NULL),
m_pColorContext(NULL),
m_pCurrentLock(NULL),
m_ePixelFormat(ePixFormat)
{
HRESULT hr = S_OK;
//
// Make sure we have an imaging factory to work with...
//
if (SUCCEEDED(hr = CreateImagingFactory()))
{
//
// ...and that the underlying bitmap is created and intialized.
//
hr = Initialize(m_ePixelFormat, cWidth, cHeight, dpiX, dpiY);
}
if (FAILED(hr))
{
throw CXDException(hr);
}
}
/*++
Routine Name:
CBmpConverter::CBmpConverter
Routine Description:
CBmpConverter constructor
Arguments:
pStream - Stream containing the bitmap container data
Return Value:
None
Throws an exception on error.
--*/
CBmpConverter::CBmpConverter(
__in IStream* pStream
) :
m_pImagingFactory(NULL),
m_pBitmap(NULL),
m_pColorContext(NULL),
m_pCurrentLock(NULL),
m_ePixelFormat(kWICPixelFormatDontCare)
{
HRESULT hr = S_OK;
//
// Make sure we have an imaging factory to work with...
//
if (SUCCEEDED(hr = CreateImagingFactory()))
{
//
// ...and that the underlying bitmap is created and intialized from the input stream.
//
hr = Initialize(pStream);
}
if (FAILED(hr))
{
throw CXDException(hr);
}
}
/*++
Routine Name:
CBmpConverter::CBmpConverter
Routine Description:
CBmpConverter constructor
Arguments:
converter - Converter class to construct from
Return Value:
None
Throws an exception on error.
--*/
CBmpConverter::CBmpConverter(
__in CONST CBmpConverter& converter
) :
m_pImagingFactory(converter.m_pImagingFactory),
m_pBitmap(converter.m_pBitmap),
m_pColorContext(converter.m_pColorContext),
m_pCurrentLock(converter.m_pCurrentLock),
m_ePixelFormat(converter.m_ePixelFormat)
{
ASSERTMSG(m_pCurrentLock == NULL, "Copying locked bitmap can lead to a deadlock when writing out the bitmap.\n");
}
/*++
Routine Name:
CBmpConverter::~CBmpConverter
Routine Description:
CBmpConverter destructor
Arguments:
None
Return Value:
None
--*/
CBmpConverter::~CBmpConverter()
{
}
/*++
Routine Name:
CBmpConverter::Initialize
Routine Description:
Initializes the bitmap given format, dimensions and resolution
Arguments:
ePixFormat - Bitmap pixel format
cWidth - Bitmap width
cHeight - Bitmap height
dpiX - Bitmap horizontal resolution
dpiY - Bitmap vertical resolution
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CBmpConverter::Initialize(
__in CONST EWICPixelFormat& ePixFormat,
__in CONST UINT& cWidth,
__in CONST UINT& cHeight,
__in CONST DOUBLE& dpiX,
__in CONST DOUBLE& dpiY
)
{
HRESULT hr = S_OK;
if (ePixFormat <= kWICPixelFormatMin ||
ePixFormat >= kWICPixelFormatMax ||
cWidth == 0 ||
cHeight == 0 ||
dpiX <= 0 ||
dpiY <= 0)
{
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)))
{
//
// Create the bitmap
//
m_pBitmap = NULL;
m_ePixelFormat = ePixFormat;
if (SUCCEEDED(hr = m_pImagingFactory->CreateBitmap(cWidth,
cHeight,
g_lutPixFrmtGuid[m_ePixelFormat],
WICBitmapCacheOnLoad,
&m_pBitmap)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_FAIL)))
{
//
// Make sure the resolution is preserved - this can lead to strange scaling
// in an XPS document if the resoution changes
//
hr = m_pBitmap->SetResolution(dpiX, dpiY);
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CBmpConverter::Initialize
Routine Description:
Initializes the bitmap from a stream containing the container information
Arguments:
pStream - Streamed container information
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CBmpConverter::Initialize(
__in IStream* pStream
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)))
{
CComPtr<IWICBitmapDecoder> pDecoder(NULL);
CComPtr<IWICBitmapFrameDecode> pBitmapSrcFrame(NULL);
LARGE_INTEGER cbMoveFromStart = {0};
//
// Ensure we have released any current color contexts
//
m_pColorContext = NULL;
//
// Create a decoder from the input stream and retrieve the first frame. Create a color context
// to recieve any potential embedded color profiles.
//
if (SUCCEEDED(hr = pStream->Seek(cbMoveFromStart, STREAM_SEEK_SET, NULL)) &&
SUCCEEDED(hr = m_pImagingFactory->CreateDecoderFromStream(pStream, NULL, WICDecodeMetadataCacheOnDemand, &pDecoder)) &&
SUCCEEDED(hr = CHECK_POINTER(pDecoder, E_FAIL)) &&
SUCCEEDED(hr = pDecoder->GetFrame(0, &pBitmapSrcFrame)) &&
SUCCEEDED(hr = CHECK_POINTER(pDecoder, E_FAIL)) &&
SUCCEEDED(hr = m_pImagingFactory->CreateColorContext(&m_pColorContext)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pColorContext, E_FAIL)))
{
//
// Check for an embedded color context
//
UINT cColContexts = 0;
if (SUCCEEDED(hr = pBitmapSrcFrame->GetColorContexts(1, &(m_pColorContext.p), &cColContexts)))
{
//
// If there are no color contexts, ensure the color context is released
//
if (cColContexts == 0)
{
m_pColorContext = NULL;
}
hr = Initialize(pBitmapSrcFrame);
}
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CBmpConverter::Initialize
Routine Description:
Intializes the bitmap from a WIC bitmap source
Arguments:
pSource - pointer to the WIC bitmap source interface to intialize from
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CBmpConverter::Initialize(
__in IWICBitmapSource* pSource
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(pSource, E_POINTER)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)))
{
//
// Make sure we have released any current bitmaps
//
m_pBitmap = NULL;
//
// Create the bitmap from the source and set the pixel format enumeration from the GUID
//
WICPixelFormatGUID guidPixFormat;
if (SUCCEEDED(hr = m_pImagingFactory->CreateBitmapFromSource(pSource, WICBitmapCacheOnDemand, &m_pBitmap)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_FAIL)) &&
SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&guidPixFormat)))
{
hr = PixelFormatFromGUID(guidPixFormat, &m_ePixelFormat);
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CBmpConverter::Write
Routine Description:
Writes the bitmap to a stream using the requested container format
Arguments:
guidContainerFormat - Requested container format to write out
pStream - The destination stream to write to
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CBmpConverter::Write(
__in REFGUID guidContainerFormat,
__inout IStream* pStream
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(pStream, E_POINTER)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)))
{
CComPtr<IWICBitmapEncoder> pEncoder(NULL);
CComPtr<IWICBitmapFrameEncode> pFrame(NULL);
CComPtr<IPropertyBag2> pPropertyBag(NULL);
UINT srcWidth = 0;
UINT srcHeight = 0;
DOUBLE xRes = 0.0;
DOUBLE yRes = 0.0;
WICPixelFormatGUID srcFormat;
//
// Create the appropriate encoder, set the stream to recieve the data and retrieve a frame.
// Initialize the frame from the current bitmap data.
//
if (SUCCEEDED(hr = m_pImagingFactory->CreateEncoder(guidContainerFormat, NULL, &pEncoder)) &&
SUCCEEDED(hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache)) &&
SUCCEEDED(hr = pEncoder->CreateNewFrame(&pFrame, &pPropertyBag)) &&
SUCCEEDED(hr = CHECK_POINTER(pFrame, E_FAIL)) &&
SUCCEEDED(hr = CHECK_POINTER(pPropertyBag, E_FAIL)) &&
SUCCEEDED(hr = pFrame->Initialize(pPropertyBag)) &&
SUCCEEDED(hr = m_pBitmap->GetSize(&srcWidth, &srcHeight)) &&
SUCCEEDED(hr = m_pBitmap->GetResolution(&xRes, &yRes)) &&
SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&srcFormat)))
{
WICRect sizeSrc = {0};
sizeSrc.Width = static_cast<INT>(srcWidth);
sizeSrc.Height = static_cast<INT>(srcHeight);
if (SUCCEEDED(hr = pFrame->SetSize(srcWidth, srcHeight)) &&
SUCCEEDED(hr = pFrame->SetResolution(xRes, yRes)) &&
SUCCEEDED(hr = pFrame->SetPixelFormat(&srcFormat)))
{
if (HasColorContext())
{
hr = pFrame->SetColorContexts(1, &m_pColorContext.p);
}
if (SUCCEEDED(hr))
{
//
// Write the bitmap data to the frame.
//
hr = pFrame->WriteSource(m_pBitmap, &sizeSrc);
}
}
}
//
// Commit the frame and the encoder - this sets the bitmap data and encodes the
// bitmap into a container
//
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = pFrame->Commit()))
{
hr = pEncoder->Commit();
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CBmpConverter::Convert
Routine Description:
Uses WIC to convert from the current pixel format to the requested pixel format
Arguments:
ePixFormat - the requested pixel format
pbCanConvert - variable that recieves whether the conversion is possible
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CBmpConverter::Convert(
__in EWICPixelFormat ePixFormat,
__out BOOL* pbCanConvert
)
{
HRESULT hr = S_OK;
if (ePixFormat > kWICPixelFormatDontCare &&
ePixFormat < kWICPixelFormatMax)
{
if (SUCCEEDED(hr = CHECK_POINTER(pbCanConvert, E_POINTER)))
{
*pbCanConvert = TRUE;
}
}
else
{
hr = E_INVALIDARG;
}
//
// If the requested format differs from the original we need to do some work.
//
if (SUCCEEDED(hr) &&
ePixFormat != m_ePixelFormat)
{
CComPtr<IWICFormatConverter> pConverter(NULL);
WICPixelFormatGUID dstFormat = g_lutPixFrmtGuid[ePixFormat];
WICPixelFormatGUID srcFormat;
//
// Retrieve a format converter, intialize from the current bitmap the use the converter
// to reset the bitmap to the appropriate type.
//
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = CHECK_POINTER(m_pImagingFactory, E_PENDING)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pBitmap, E_PENDING)) &&
SUCCEEDED(hr = m_pImagingFactory->CreateFormatConverter(&pConverter)) &&
SUCCEEDED(hr = CHECK_POINTER(pConverter, E_FAIL)) &&
SUCCEEDED(hr = m_pBitmap->GetPixelFormat(&srcFormat)) &&
SUCCEEDED(hr = pConverter->CanConvert(srcFormat, dstFormat, pbCanConvert)) &&
*pbCanConvert &&
SUCCEEDED(hr = pConverter->Initialize(m_pBitmap, dstFormat, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom)))
{
hr = Initialize(pConverter);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -