Exemplo de código de processamento de imagem
O exemplo de código a seguir mostra como implementar um filtro de processamento de imagem simples. Esse filtro de processamento de imagem dá suporte ao brilho e contraste, bem como às propriedades opcionais deskew e rotation.
Nota Partes de código são omitidas do exemplo a seguir para fins de brevidade.
///
/// Constructor
///
CImageFilter::CImageFilter(VOID) :
m_pWiaItem(NULL),
m_pAppWiaTransferCallback(NULL),
m_nRefCount(0),
m_pCurrentStream(NULL)
{
//
// Nothing
//
}
///
/// Destructor
///
CImageFilter::~CImageFilter()
{
if (m_pWiaItem)
{
m_pWiaItem->Release();
m_pWiaItem = NULL;
}
if (m_pAppWiaTransferCallback)
{
m_pAppWiaTransferCallback->Release();
m_pAppWiaTransferCallback = NULL;
}
}
//
// pWiaItem is the WIA item we are doing the download for.
// In the case of folder transfers, this will actually be
// the parent item of the images we are acquiring.
//
STDMETHODIMP
CImageFilter::InitializeFilter(
IN IWiaItem2 *pWiaItem,
IN IWiaTransferCallback *pWiaTransferCallback)
{
HRESULT hr = S_OK;
hr = (pWiaItem && pWiaTransferCallback) ? S_OK : E_INVALIDARG;
//
// InitializeFilter should only be called only once, but,
// to be safe, we release any old resources we might still
// reference before we take references to the new resources.
//
if (SUCCEEDED(hr))
{
if (m_pWiaItem)
{
m_pWiaItem->Release();
m_pWiaItem = NULL;
}
if (m_pAppWiaTransferCallback)
{
m_pAppWiaTransferCallback->Release();
m_pAppWiaTransferCallback = NULL;
}
m_pWiaItem = pWiaItem;
m_pWiaItem->AddRef();
m_pAppWiaTransferCallback = pWiaTransferCallback;
m_pAppWiaTransferCallback->AddRef();
}
return hr;
}
STDMETHODIMP
CImageFilter::FilterPreviewImage(
IN IWiaItem2 *pWiaChildItem,
IN RECT InputImageExtents,
IN IStream *pInputStream)
{
IStream *pAppStream = NULL;
BSTR bstrItemName = NULL;
BSTR bstrFullItemName = NULL;
LONG xpos = 0, ypos = 0, width = 0, height = 0;
LONG lBrightness = 0;
LONG lContrast = 0;
LONG lDeskewX = 0;
LONG lDeskewY = 0;
LONG lRotation = PORTRAIT;
HRESULT hr;
hr = m_pAppWiaTransferCallback ? S_OK : E_UNEXPECTED;
//
// Read all of the properties we need.
//
if (SUCCEEDED(hr))
{
hr = ReadAllProperties(pWiaChildItem,
&xpos,
&ypos,
&width,
&height,
&bstrItemName,
&bstrFullItemName,
&lBrightness,
&lContrast,
&lRotation,
&lDeskewX,
&lDeskewY);
}
//
// If the upper left corner of the passed image does
// not correspond to (0,0) on the flatbed, adjust
// xpos and ypos accordingly in order to "cut out"
// the correct region represented by pWiaChildItem
// from pInputStream.
//
if (SUCCEEDED(hr))
{
xpos = xpos - InputImageExtents.left;
ypos = ypos - InputImageExtents.top;
}
//
// Now get the application stream and write to it.
//
if (SUCCEEDED(hr))
{
hr = m_pAppWiaTransferCallback->GetNextStream(
0,
bstrItemName,
bstrFullItemName,
&pAppStream);
}
if (SUCCEEDED(hr))
{
//
// DoFiltering is where the actual filtering is done.
// This function is left out to simplify this example.
// DoFiltering reads the unfiltered image data from
// pInputStream and writes the filtered (and possibly
// deskewed) image into pAppStream.
//
// Note: A "real" implementation of DoFiltering should send
// WIA_TRANSFER_MSG_STATUS messages to the application's
// callback interface, m_pAppWiaTransferCallback.
// DoFiltering should preferably also be able to
// work on bands of data in the case where there is no
// rotation or deskewing being performed.
//
hr = DoFiltering(lBrightness,
lContrast,
lDeskewX,
lDeskewY,
pInputStream,
pAppStream,
xpos,
ypos,
width,
height,
lRotation);
}
if (pAppStream)
{
pAppStream->Release();
}
return hr;
}
//
// Our simple image processing filter implementation always
// caches all data internally, and it does not write data back
// to the application's stream until it receives
// WIA_TRANSFER_MSG_END_OF_STREAM. A "real" image-processing
// filter should be able to work on bands of data -- at least
// if there is no rotation or deskew set into the item.
//
// In order to find out how many bytes have been written
// into the application's stream, we store an interface
// pointer to the current filtering stream, m_pCurrentStream.
// When we reach the end of the stream, we must notify the
// filtering stream that it should filter and write all of
// its image data to the application stream, if it has not
// already done so.
//
STDMETHODIMP
CImageFilter::TransferCallback(
IN LONG lFlags,
IN WiaTransferParams *pWiaTransferParams)
{
HRESULT hr;
hr = m_pAppWiaTransferCallback ? S_OK : E_UNEXPECTED;
if (SUCCEEDED(hr))
{
//
// Note: The percent reflects the amount of scanning
// the driver reports, whereas the "BytesWritten" member
// is the actual number of bytes that we have written
// to the application's stream.
// We do not modify the percent, however we have to
// modify the ulBytesWrittenToCurrentStream member.
//
if ((pWiaTransferParams->lMessage ==
WIA_TRANSFER_MSG_END_OF_STREAM) &&
m_pCurrentStream )
{
hr = m_pCurrentStream->Flush();
}
else if (m_pCurrentStream)
{
pWiaTransferParams->ulBytesWrittenToCurrentStream =
m_pCurrentStream->m_cBytesWritten;
}
hr = m_pAppWiaTransferCallback->TransferCallback(
lFlags,
pWiaTransferParams);
if (m_pCurrentStream &&
(pWiaTransferParams->lMessage ==
WIA_TRANSFER_MSG_END_OF_STREAM))
{
m_pCurrentStream->Release();
m_pCurrentStream = NULL;
}
}
return hr;
}
//
// GetNextStream creates a filtering stream whose Write method
// writes to the application's stream. Because the item
// represented by bstrFullItemName might be a child item of
// the item passed into InitializeFilter, we have to call
// FindItemByName to retrieve the actual item.
//
STDMETHODIMP
CImageFilter::GetNextStream(
IN LONG lFlags,
IN BSTR bstrItemName,
IN BSTR bstrFullItemName,
OUT IStream **ppDestination)
{
HRESULT hr;
IStream *pAppStream = NULL;
IStream *pCachingStream = NULL;
IWiaItem2 *pCurrentWiaItem = NULL;
LONG lBrightness = 0;
LONG lContrast = 0;
LONG lDeskewX = 0;
LONG lDeskewY = 0;
LONG lRotation = PORTRAIT;
hr = m_pAppWiaTransferCallback ? S_OK : E_UNEXPECTED;
if (m_pCurrentStream)
{
m_pCurrentStream->Release();
m_pCurrentStream = NULL;
}
if (SUCCEEDED(hr))
{
hr = m_pAppWiaTransferCallback->GetNextStream(
lFlags,
bstrItemName,
bstrFullItemName,
&pAppStream);
}
if (SUCCEEDED(hr))
{
hr = m_pWiaItem->FindItemByName(
0,
bstrFullItemName,
&pCurrentWiaItem);
}
//
// Here we read all properties from pCurrentWiaItem
// that we need in order to do the filtering.
// Note: We do not need to read all the properties
// like we did in update preview. The driver should
// always return the area represented by the bounding
// rectangle, so no "cutting" will be done in this case.
//
if (SUCCEEDED(hr))
{
hr = ReadDownloadProperties(pCurrentWiaItem,
&lBrightness,
&lContrast,
&lRotation,
&lDeskewX,
&lDeskewY);
}
if (SUCCEEDED(hr))
{
hr = CreateStreamOnHGlobal(0, TRUE, &pCachingStream);
if (SUCCEEDED(hr))
{
//
// The implementation of CalculateAndSetSize is
// omitted here. CalculateAndSetSize estimates the
// maximum size of the image we are about to download;
// then it calls SetSize on the caching stream.
// This size calculation is for performance reasons
// (if the image we are downloading is very large).
// A "real" image processing filter should probably
// use a higher-performance stream implementation.
//
CalculateAndSetSize(pCurrentWiaItem, pCachingStream);
}
}
if (SUCCEEDED(hr))
{
m_pCurrentStream = new CMyFilterStream(
pAppStream,
pCachingStream,
lBrightness,
lContrast,
lRotation,
lDeskewX,
lDeskewY);
if (m_pCurrentStream)
{
hr = m_pCurrentStream->QueryInterface(
IID_IStream,
(void**)ppDestination);
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (pAppStream)
{
pAppStream->Release();
}
if (pCachingStream)
{
pCachingStream->Release();
}
if (pCurrentWiaItem)
{
pCurrentWiaItem->Release();
}
return hr;
}
//
// FILTERING STREAM IMPLEMENTATION
//
///
/// Constructor - Note: Sets reference count to 1.
///
CMyFilterStream::CMyFilterStream(
IStream *pAppStream,
IStream *pCachingStream,
LONG lBrightness,
LONG lContrast,
LONG lRotation,
LONG lDeskewX,
LONG lDeskewY) :
m_pAppStream(pAppStream),
m_pCachingStream(pCachingStream),
m_nRefCount(1),
m_cBytesWritten(0),
m_lBrightness(lBrightness),
m_lContrast(lContrast),
m_lRotation(lRotation),
m_lDeskewX(lDeskewX),
m_lDeskewY(lDeskewY)
{
if (m_pAppStream)
{
m_pAppStream->AddRef();
}
if (m_pCachingStream)
{
m_pCachingStream->AddRef();
}
}
///
/// Destructor
///
CMyFilterStream::~CMyFilterStream()
{
if (m_pAppStream)
{
m_pAppStream->Release();
}
if (m_pCachingStream)
{
m_pCachingStream->Release();
}
}
//
// The only IStream method of interest here is Write.
// For this simple ImageProcesing filter, we always write the
// data into the "caching stream". The filtered image data is
// not written into the application's stream until we receive
// an end-of-stream message.
//
STDMETHODIMP
CMyFilterStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
{
return m_pCachingStream->Write(pv, cb, pcbWritten);
}
//
// Flush is called when our callback routine receives
// WIA_TRANSFER_MSG_END_OF_STREAM. In this simple implementation,
// this is when we first write the data to the application's
// stream, m_pAppStream.
//
HRESULT
CMyFilterStream::Flush(VOID)
{
HRESULT hr;
hr = DoFiltering(m_pAppWiaTransferCallback,
m_lBrightness,
m_lContrast,
m_lRotation,
m_lDeskewX,
m_lDeskewY,
m_pCachingStream,
m_pAppStream);
if (m_pAppStream)
{
m_pAppStream->Release();
m_pAppStream = NULL;
}
if (m_pCachingStream)
{
m_pCachingStream->Release();
m_pCachingStream = NULL;
}
return hr;
}