⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imagefilter.cpp

📁 winddk src目录下的WDM源码压缩!
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************
 *
 *  imagefilter.cpp
 *
 *  Copyright (c) 2003 Microsoft Corporation.  All Rights Reserved.
 *
 *  DESCRIPTION:
 *
 *  Contains implementation of Image Processing Filer with "filtering stream".
 *  The implementation uses GDI+ for cutting out images, for deskewing as well
 *  as for implementing brightness and contrast. 
 *  
 *******************************************************************************/
#include "stdafx.h"
#include <gdiplus.h>
#include <math.h>

#include "imagefilter.h"
#include "wiaitem.h"
#include "gphelper.h"

using namespace Gdiplus;

/*****************************************************************************
 *  
 *  @func STDMETHODIMP | DoFiltering | Reads unfiltered data from input stream, cuts, deskews, rotates and filters the image data
 *                                     and then writes fitlered data to output stream.
 *
 *  @parm   LONG | lBrightness |
 *          The brightness set into the region we are filtering. Should be between -1000 and 1000
 * 
 *  @parm   LONG | lContrast |
 *          The contrast set into the region we are filtering. Should be between -1000 and 1000
 * 
 *  @parm   LONG | regionRotate |
 *          How much we should rotate the reion (note rotate happens after deskew!)
 * 
 *  @parm   LONG | regionDeskewX |
 *          WIA_IPS_DESKEW_X for region to deskew (note 0 means no deskew)
 * 
 *  @parm   LONG | regionDeskewY |
 *          WIA_IPS_DESKEW_Y for region to deskew (note 0 means no deskew)
 * 
 *  @parm   IStream* | pInputStream |
 *          Unfiltered image data, either directly from driver of from WIA Preview Component
 *
 *  
 *  @parm   IStream* | pOutputStream |
 *          Application stream where we write image data
 *
 *  @parm   LONG | inputXPOS |
 *          X-position of upper left corner of region to "cut-out" from image in pInputStream.
 *          Note that this parameter is relative to image in pInputStream which is not necessarily
 *          its X-position on the flatbed.
 *  
 *  @parm   LONG | inputYPOS |
 *          Y-position of upper left corner of region to "cut-out" from image in pInputStream.
 *          Note that this parameter is relative to image in pInputStream which is not necessarily
 *          its Y-position on the flatbed.
 * 
 *  @parm   LONG | boundingRegionWidth |
 *          Width of bounding area to "cut-out" from pInputStream. A value of 0 means that we should not perform
 *          any cutting, but instead filter the whole image.
 *          boundingRegionWidth will be set to 0 when we receive the image data from the driver since the driver
 *          will only send us the bounding rectangle of the selected region and not the entire flatbed.
 *          Note: if there is not deskewing being performed this is the "actual" width of the region.
 * 
 *  @parm   LONG | boundingRegionHeight |
 *          Height of bounding area to "cut-out" from pInputStream. A value of 0 means that we should not perform
 *          any cutting, but instead filter the whole image.
 *          boundingRegionHeight will be set to 0 when we receive the image data from the driver since the driver
 *          will only send us the bounding rectangle of the selected region and not the entire flatbed. 
 *          Note: if there is not deskewing being performed this is the "actual" height of the region.
 *
 *  @comm
 *  Note, our simple implementation of DoFiltering always write all the data
 *  in one chunk to the application. An actual image processing filter should
 *  be able to work on bands of data in the case where there is no rotation
 *  or deskewing being performed.
 *  This implementation also does not send callbacks (TransferCallback) messages
 *  to the application indicating progress. A "real" implementation should do that!
 *
 *  @rvalue S_OK    | 
 *              The function succeeded.
 *  @rvalue E_XXX   | 
 *              The function failed 
 * 
 *****************************************************************************/

static HRESULT DoFiltering(
			LONG        lBrightness,
			LONG        lContrast,
			LONG        regionRotate,
			LONG        regionDeskewX,
			LONG        regionDeskewY,
    __in	IStream     *pInputStream,
    __in	IStream     *pOutputStream,
    __inout ULONG64     *pulBytesWrittenToOutputStream,
			LONG        inputXPOS = 0,
			LONG        inputYPOS = 0,
			LONG        boundingRegionWidth = 0,
			LONG        boundingRegionHeight = 0
    )
{
    HRESULT                 hr                  = S_OK;

    Bitmap                  *pOriginalBitmap    = NULL;
    Bitmap                  *pTargetBitmap      = NULL;
    CLSID                   formatEncoder       = {0};
    GdiplusStartupInput     gdiplusStartupInput;
    ULONG_PTR               ulImageLibraryToken = 0;

    if (SUCCEEDED(hr))
    {
        hr = GDISTATUS_TO_HRESULT(GdiplusStartup(&ulImageLibraryToken, &gdiplusStartupInput, NULL));
    }

    //
    // Create a Bitmap object on the unfiltered input stream
    //
    if (SUCCEEDED(hr))
    {
        pOriginalBitmap = new Bitmap(pInputStream, TRUE);

        if (pOriginalBitmap)
        {
            hr = GDISTATUS_TO_HRESULT(pOriginalBitmap->GetLastStatus());
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }

        if (SUCCEEDED(hr))
        {
            hr = GDISTATUS_TO_HRESULT(GetEncoderGUIDFromImage(pOriginalBitmap, &formatEncoder));
        }
    }

    //
    // If boundingRegionWidth or boundingRegionHeight is 0, this means that we should not perform any
    // "cutting" but instead just filter the whole input image.
    //
    if (SUCCEEDED(hr))
    {
        if ((0 == boundingRegionWidth) || (0 == boundingRegionHeight))
        {
            inputXPOS = 0;
            inputXPOS = 0;
            boundingRegionWidth  = pOriginalBitmap->GetWidth();
            boundingRegionHeight = pOriginalBitmap->GetHeight();
        }
    }

    //
    // Perform filtering. This is done in 3 steps:
    // 1. Create a new bitmap with the dimensions of the final, filtered image.
    // 2. "Cut-out" and deskew final image from full image. This is done by a translate
    //    followed by a rotate transformtation.
    // 3. Apply color matrix to to perform brightness and contrast modifications.
    //
    if (SUCCEEDED(hr))
    {
        PixelFormat     originalPixelFormat = pOriginalBitmap->GetPixelFormat();

        double dblDeskewAngle        = 0.0;
        LONG   lXdelta               = 0;
        LONG   lYdelta               = 0;
        LONG   lActualRegionWidth    = 0;
        LONG   lActualRegionHeight   = 0;

        //
        // No deskew, just cut out a rectangular area!
        //
        if ((regionDeskewX) == 0 || (regionDeskewY == 0))
        {
            lActualRegionWidth  = boundingRegionWidth;
            lActualRegionHeight = boundingRegionHeight;
            dblDeskewAngle = 0.0;
        }
        else
        {
            if (regionDeskewX > regionDeskewY)
            {
                lYdelta = regionDeskewY;

                dblDeskewAngle = atan2((double)regionDeskewY, (double)regionDeskewX);

                lActualRegionWidth  = (LONG) sqrt((double) (regionDeskewX * regionDeskewX + regionDeskewY * regionDeskewY));
                lActualRegionHeight = (LONG) (((double) (boundingRegionHeight - regionDeskewY)) / cos(dblDeskewAngle));
            }
            else         
            {
                lXdelta = regionDeskewX;

                dblDeskewAngle = atan2((double)regionDeskewX, (double)regionDeskewY);

                lActualRegionWidth  = (LONG) (((double) (boundingRegionWidth - regionDeskewX)) / cos(dblDeskewAngle)); 
                lActualRegionHeight = (LONG) sqrt((double) (regionDeskewX * regionDeskewX + regionDeskewY * regionDeskewY));

                dblDeskewAngle = -dblDeskewAngle;
            }
        }

        pTargetBitmap = new Bitmap(lActualRegionWidth, lActualRegionHeight, originalPixelFormat);

        if (pTargetBitmap)
        {
            hr = GDISTATUS_TO_HRESULT(pTargetBitmap->GetLastStatus());
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }

        

        if (SUCCEEDED(hr))
        {
            Graphics        graphics(pTargetBitmap);
            ImageAttributes imageAttributes;

            hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus());

            if (SUCCEEDED(hr))
            {
                graphics.TranslateTransform((REAL)-(inputXPOS + lXdelta), (REAL)-(inputYPOS + lYdelta));
                hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus());
            }


            if (dblDeskewAngle != 0.0)
            {
                if (SUCCEEDED(hr))
                {
                    graphics.RotateTransform((REAL)(dblDeskewAngle * 180.0 / PI), MatrixOrderAppend);
                    hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus());
                }
            }

            if (SUCCEEDED(hr))
            {
                //
                // Calculate the values needed for the matrix
                //
                REAL scale = 0.0;
                REAL trans = 0.0;

                //
                // Normalize brightness and contrast to 0 to 1000.
                // This assumes valid settings are - 1000 to 1000.
                //
                CalculateBrightnessAndContrastParams( (lBrightness + 1000) /2, (lContrast + 1000) / 2, &scale, &trans );
    
                //
                // Prepare the matrix for brightness and contrast transforms
                //
                ColorMatrix brightnessAndContrast = {scale, 0,     0,     0,     0,
                                                     0,     scale, 0,     0,     0,
                                                     0,     0,     scale, 0,     0,
                                                     0,     0,     0,     1,     0,
                                                     trans, trans, trans, 0,     1};
    
                hr = imageAttributes.SetColorMatrix(&brightnessAndContrast);
            }
            
            if (SUCCEEDED(hr))
            {
                UINT    uWidth  = pOriginalBitmap->GetWidth();
                UINT    uHeight = pOriginalBitmap->GetHeight();

                Rect rect( 0, 0, uWidth, uHeight );

                hr = GDISTATUS_TO_HRESULT(graphics.DrawImage(pOriginalBitmap,rect,0,0,uWidth, uHeight,UnitPixel,&imageAttributes));
            }
        }
        
        
    }

    //
    // The last step for us to perform is rotating the region
    //
    if (SUCCEEDED(hr) && (regionRotate != PORTRAIT))
    {
        RotateFlipType  rotateFlipType;

        switch (regionRotate)
        {
            case LANSCAPE:
                rotateFlipType = Rotate270FlipNone;
                break;
            case ROT180:
                rotateFlipType = Rotate180FlipNone;
                break;
            case ROT270:                            
                rotateFlipType = Rotate90FlipNone;
                break;
            default:
                //
                // We should never get here!
                //
                rotateFlipType = RotateNoneFlipNone;
        }

        hr = GDISTATUS_TO_HRESULT(pTargetBitmap->RotateFlip(rotateFlipType));
    }

    //
    // The GDI+ Bitmap::Save method does not work very well for images that
    // an application displays band by band since it results in a large number
    // of small Write calls. Instead we do a LockBits to read the bits from
    // the bitmap and then write them to the application's stream.
    //
    if (SUCCEEDED(hr))
    {
        hr = WriteBitmapToStream(pTargetBitmap, pOutputStream, pulBytesWrittenToOutputStream);
    }
    
    if (pOriginalBitmap)
    {
        delete pOriginalBitmap;
    }

    if (pTargetBitmap)
    {
        delete pTargetBitmap;
    }

    if(ulImageLibraryToken)
    {
        GdiplusShutdown(ulImageLibraryToken);
        ulImageLibraryToken = 0;
    }

    return hr;
}

/*****************************************************************************
 *
 * CMyFilterStream is our implemetation of the filtering stream.
 * The only IStream method that it implements is Write().
 *
 * The stream keeps a reference to the applications stream into which it writes
 * the filtered data (the header is not modified however).
 *  
 *******************************************************************************/

///
///  Constructor - note sets reference count to 1
///
CMyFilterStream::CMyFilterStream(
    VOID) : m_pAppStream(NULL) , m_pCachingStream(NULL), m_nRefCount(1), m_cBytesWritten(0),
            m_lBrightness(0), m_lContrast(0), m_lRotation(0), m_lDeskewX(0), m_lDeskewY(0)
{
}

///
///  Destructor:
///
CMyFilterStream::~CMyFilterStream(
    VOID)
{
    if (m_pAppStream)
    {
        m_pAppStream->Release();
        m_pAppStream = NULL;
    }

    if (m_pCachingStream)
    {
        m_pCachingStream->Release();
        m_pCachingStream = NULL;
    }
}

///
/// Initilize stores a reference to the application's stream. It also creates
/// its own stream with CreateStreamOnHGlobal into which it stores all the
/// unfiltered image data before it performs its filtering (in Flush).
///
HRESULT
CMyFilterStream::Initialize(
    __in	IStream      *pAppStream,
			LONG         lBrightness,
			LONG         lContrast,
			LONG         lRotation,
			LONG         lDeskewX,
			LONG         lDeskewY,
			LONG         lXExtent,
			LONG         lYExtent,
			LONG         lBitDepth)
{
    HRESULT     hr = S_OK;

    hr = pAppStream ? S_OK : E_INVALIDARG;

    if (SUCCEEDED(hr))
    {
        m_pAppStream = pAppStream;
        m_pAppStream->AddRef();
    }

    if (SUCCEEDED(hr))
    {
        hr = CreateStreamOnHGlobal(0, TRUE, &m_pCachingStream);

        //
        // For large images it is important that we make a good estimate of the image size,
        // otherwise memory re-allocations may become very expensive.
        //
        if (SUCCEEDED(hr))
        {
            ULARGE_INTEGER ullSize = {0};
            LARGE_INTEGER  ullPos  = {0};

            ullSize.QuadPart = GetUpperLimitSize(lXExtent, lYExtent, lBitDepth);

            hr = m_pCachingStream->SetSize(ullSize);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -