Sample Code

Windows Driver Samples/ Windows Image Acquisition (WIA) Driver Samples/ C++/ wiadriverex/ imgfilter/ gphelper.h/

using namespace Gdiplus;

#define BUFFER_SIZE  (128 * 1024)

/*****************************************************************************
 *
 *  @func Gdiplus::Status | GetEncoderGUIDFromImage | Retrieves the encoder for a Bitmap
 *
 *  @parm   Bitmap | pOriginalBitmap |
 *          The Bitmap for which to get its encoder
 *
 *  @parm   CLSID | pFormatEncoder |
 *          On successful return this contains the GUID of the encoder for
 *          pOriginalBitmaps image type
 *
 *  @comm
 *  This function is used to return the GDI+ encoder guid for a Bitmap.
 *
 *  @rvalue S_OK    |
 *              The function succeeded.
 *  @rvalue E_XXXXXX    |
 *              Failure to retrieve image format
 *
 *****************************************************************************/
static Status GetEncoderGUIDFromImage(
    _In_	IN  Bitmap      *pOriginalBitmap,
    _Out_ OUT CLSID       *pFormatEncoder)
{
    Status          status;
    CLSID           imageFormat;
    UINT            num = 0;          // number of image encoders
    UINT            size = 0;         // size of the image encoder array in bytes
    ImageCodecInfo* pImageCodecInfo = NULL;
    BOOL            bFound = FALSE;

    status = (pOriginalBitmap && pFormatEncoder) ? Ok : InvalidParameter;

    if (status == Ok)
    {
        status = pOriginalBitmap->GetRawFormat(&imageFormat);
    }

    if (status == Ok)
    {
        status = GetImageEncodersSize(&num, &size);

        if ((status == Ok) && (size == 0))
        {
            status = GenericError;
        }
    }

    if (status == Ok)
    {
        pImageCodecInfo = (ImageCodecInfo*)(malloc(size));

        status = pImageCodecInfo ? Ok : OutOfMemory;
    }

    if (status == Ok)
    {
        status = GetImageEncoders(num, size, pImageCodecInfo);
    }

    if (status == Ok)
    {
        for(UINT j = 0; (j < num) && !bFound ; ++j)
        {
            _Analysis_assume_(size >= (num * sizeof(ImageCodecInfo))); 
            if( pImageCodecInfo[j].FormatID == imageFormat )
            {
                *pFormatEncoder = pImageCodecInfo[j].Clsid;
                bFound = TRUE;
            }
        }
    }

    if (status == Ok)
    {
        status = bFound ? Ok : UnknownImageFormat;
    }

    if (pImageCodecInfo)
    {
        free(pImageCodecInfo);
    }

    return status;
}


/*****************************************************************************
 *
 *  @func HRESULT | GetUpperLimitSize | Returns an estimate of the maximum size of a BMP
 *          image. The result of this function should be used in a subsequent call to
 *          IStream::SetSize to ensure that the stream does not have to do any reallocations
 *          of memory, which can be very expensive
 *
 *  @parm   ULONG | uWidth |
 *          Image width in pixels
 *
 *  @parm   ULONG | uHeight |
 *          Image height in pixels
 *
 *  @parm   ULONG | uBitsPerPixel |
 *          Number of bits per pixel
 * *
 *  @rvalue ULONG    |
 *              Estimated upper limit of image size.
 *
 *****************************************************************************/
static inline ULONG GetUpperLimitSize( ULONG uWidth, ULONG uHeight, ULONG uBitsPerPixel )
{
       return ( /*Safety factor of 1.33 = 8/6*/ uWidth * uHeight * uBitsPerPixel / 6 ) + /*Safety amount for overhead*/ 2048;
}


static inline HRESULT GDISTATUS_TO_HRESULT(Gdiplus::Status status)
{
    //
    // Default to turning GDI+ errors into generic failures
    //
    HRESULT hr = E_FAIL;

    switch( status )
    {
        case Gdiplus::Ok:
            hr = S_OK;
            break;

        case Gdiplus::InvalidParameter:
            hr = E_INVALIDARG;
            break;

        case Gdiplus::OutOfMemory:
            hr = E_OUTOFMEMORY;
            break;

        case Gdiplus::InsufficientBuffer:
            hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            break;

        case Gdiplus::Aborted:
            hr = E_ABORT;
            break;

        case Gdiplus::ObjectBusy:
            hr = E_PENDING;
            break;

        case Gdiplus::FileNotFound:
            hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
            break;

        case Gdiplus::AccessDenied:
            hr = E_ACCESSDENIED;
            break;

        case Gdiplus::UnknownImageFormat:
            hr = HRESULT_FROM_WIN32(ERROR_INVALID_PIXEL_FORMAT);
            break;

        case Gdiplus::NotImplemented:
            hr = E_NOTIMPL;
            break;

        case Gdiplus::Win32Error:
            hr = HRESULT_FROM_WIN32(GetLastError());
            break;

        case Gdiplus::ValueOverflow:
        case Gdiplus::FontFamilyNotFound:
        case Gdiplus::FontStyleNotFound:
        case Gdiplus::NotTrueTypeFont:
        case Gdiplus::UnsupportedGdiplusVersion:
        case Gdiplus::GdiplusNotInitialized:
        case Gdiplus::WrongState:
            break;
    }
    return hr;
}

static inline void CalculateBrightnessAndContrastParams( INT iBrightness, INT iContrast, _Out_ float *scale, _Out_ float *translate )
{
    //
    // force values to be at least 1, to avoid undesired effects
    //
    if (iBrightness < 1)
    {
        iBrightness = 1;
    }
    if (iContrast < 1)
    {
        iContrast = 1;
    }

    //
    // get current brightness as a percentage of full scale
    //
    float fBrightness = (float)( 1000 - iBrightness ) / 1000.0f;
    if (fBrightness > 0.95f)
    {
        fBrightness = 0.95f; /* clamp */
    }

    //
    // get current contrast as a percentage of full scale
    //
    float fContrast = (float) iContrast / 1000.0f;
    if (fContrast > 1.0f)
    {
        fContrast = 1.0;    /* limit to 1.0    */
    }

    //
    // convert contrast to a scale value
    //
    if (fContrast <= 0.5f)
    {
        *scale = fContrast / 0.5f;    /* 0 -> 0, .5 -> 1.0 */
    }
    else
    {
        if (fContrast == 1.0f)
        {
                fContrast = 0.9999f;
        }
        *scale = 0.5f / (1.0f - fContrast); /* .5 -> 1.0, 1.0 -> inf */
    }

    *translate = 0.5f - *scale * fBrightness;
}

/*****************************************************************************
 *
 *  @func HRESULT | GetBitmapHeaderFromBitmapData | Fills in BITMAPINFOHEADER from BitmapData object
 *
 *  @parm   BitmapData* | pGDIPlusBitmapData |
 *          Pointer to a GDI+ BitmapData object
 *
 *
 *  @parm   BITMAPINFOHEADER* | pBitmapInfoHeader |
 *          Pointer to a BITMAPINFOHEADER structure
 *
 *  @comm
 *  This function populates a BITMAPINFOHEADER structure
 *  using data contained in a Gdiplus::BitmapData object.
 *  This function only works with 24-bit data.
 *
 *  @rvalue S_OK    |
 *              The function succeeded.
 *  @rvalue E_XXXXXX    |
 *              The function failed
 *
 *****************************************************************************/
HRESULT GetBitmapHeaderFromBitmapData(
    _In_	Gdiplus::BitmapData     *pGDIPlusBitmapData,
    _Out_ BITMAPINFOHEADER          *pBitmapInfoHeader)
{
    HRESULT hr = E_INVALIDARG;
    if((pGDIPlusBitmapData) && (pBitmapInfoHeader) && (pGDIPlusBitmapData->PixelFormat == PixelFormat24bppRGB))
    {
        memset(pBitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER));
        pBitmapInfoHeader->biSize       = sizeof(BITMAPINFOHEADER);
        pBitmapInfoHeader->biPlanes     = 1;
        pBitmapInfoHeader->biWidth      = pGDIPlusBitmapData->Width;
        pBitmapInfoHeader->biHeight     = pGDIPlusBitmapData->Height;

        // We cannot use the stride to calculate the size, because if there is no
        // format conversion, we might get the original bits...
        // We need to calculate the size based on the width
        pBitmapInfoHeader->biSizeImage  = ((((pGDIPlusBitmapData->Width * 3) + 3) & ~3) * pGDIPlusBitmapData->Height);

        pBitmapInfoHeader->biBitCount   = 24;
        hr = S_OK;
    }

    return hr;
}

/*****************************************************************************
 *
 *  @func HRESULT | WriteBitmapToStream | WriteBitmapToStream writes the data from the Bitmap object pTargetBitmap into the IStream pOutputStream
 *
 *  @parm   Bitmap* | pTargetBitmap |
 *          Pointer to a GDI+ Bitmap object
 *
 *
 *  @parm   IStream* | pOutputStream |
 *          Pointer to IStream provided by application. We write the data from pTargetBitmap
 *          into this stream
 *
 *  @comm
 *  We use this function since the GDI+ method 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.
 *
 *  @rvalue S_OK    |
 *              The function succeeded.
 *  @rvalue E_XXXXXX    |
 *              The function failed
 *
 *****************************************************************************/
HRESULT
WriteBitmapToStream(
    _In_    Gdiplus::Bitmap *pTargetBitmap,
    _In_    IStream         *pOutputStream,
    _Inout_ ULONG64         *pulBytesWrittenToOutputStream)

{
    HRESULT          hr = S_OK;

    Gdiplus::Rect    rFrame(0, 0, pTargetBitmap->GetWidth(), pTargetBitmap->GetHeight());
    BitmapData       bitmapData = {0};
    BITMAPINFOHEADER bmih = {0};
    BITMAPFILEHEADER bmfh = {0};
    BOOL             bBitsLocked = FALSE;
    DWORD            dwTotalBytes = 0;
    DWORD            dwTotalBytesRead = 0;
    DWORD            dwLinesRead = 0;
    BYTE             *pBitmapBits = NULL;
    ULONG            cbWritten = 0;
    INT              iScanline = 0;
    DWORD            dwNumLineBytesInBuffer = 0;
    DWORD            dwNumBytesLeftToRead = 0;
    BYTE             *pBuffer = NULL;

    if (!pTargetBitmap || !pOutputStream || !pulBytesWrittenToOutputStream)
    {
        hr = E_INVALIDARG;
    }

    if (SUCCEEDED(hr))
    {
        pBuffer = (BYTE*) LocalAlloc(LPTR, BUFFER_SIZE);

        hr = pBuffer ? S_OK : E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        hr = GDISTATUS_TO_HRESULT(pTargetBitmap->LockBits(&rFrame, ImageLockModeRead, PixelFormat24bppRGB, &bitmapData));
    }

    if (SUCCEEDED(hr))
    {
        bBitsLocked = TRUE;
        hr = GetBitmapHeaderFromBitmapData(&bitmapData,&bmih);
    }

    if (SUCCEEDED(hr))
    {
        pBitmapBits     = (BYTE*)bitmapData.Scan0;
        bmfh.bfType     = ((WORD) ('M' << 8) | 'B');
        bmfh.bfOffBits  = sizeof(bmfh) + sizeof(bmih);
        bmfh.bfSize     = bmfh.bfOffBits + bmih.biSizeImage;

        dwTotalBytes        = bmfh.bfSize;
        dwTotalBytesRead    = 0;
        dwLinesRead         = 0;
        //
        // iScanline contains the number of bytes to copy from each scanline
        //
        iScanline = ((bitmapData.Width * 3) + 3) & ~3;

        if (iScanline > BUFFER_SIZE)
        {
            //
            // We don't have enough space in our temporary scanline buffer
            //
            hr = E_OUTOFMEMORY;
        }
        else
        {
            //
            //  Calculate number of bytes in whole scan lines.
            //
            dwNumLineBytesInBuffer    = (BUFFER_SIZE - (BUFFER_SIZE % iScanline));
        }
    }

    if (SUCCEEDED(hr))
    {
        LARGE_INTEGER li = {0};
        hr = pOutputStream->Seek(li, STREAM_SEEK_END, NULL);
    }

    //
    // First write bitmap headers
    //
    if (SUCCEEDED(hr))
    {
        hr = pOutputStream->Write(&bmfh, sizeof(bmfh), &cbWritten);
        dwTotalBytesRead += sizeof(bmfh);
    }

    if (SUCCEEDED(hr))
    {
        hr = pOutputStream->Write(&bmih, sizeof(bmih), &cbWritten);
        dwTotalBytesRead += sizeof(bmih);
    }

    while (SUCCEEDED(hr) && (dwTotalBytesRead < dwTotalBytes))
    {
        dwNumBytesLeftToRead      = (dwTotalBytes - dwTotalBytesRead);

        //
        //  Set how many bytes we are going to read.  This is either the maxiumun
        //  nunmber of scan lines that will fit into the buffer, or it's the number
        //  of bytes left in the last chunk.
        //
        if(dwNumBytesLeftToRead < dwNumLineBytesInBuffer)
        {
            dwNumLineBytesInBuffer = dwNumBytesLeftToRead;
        }

        //
        //  Position buffer pointer to correct data location for this band.  We are copying
        //  in reverse scanline order so that the bitmap becomes topdown (it is currently
        //  upside-down in the source buffer).
        //
        BYTE *pBits = pBitmapBits + (bitmapData.Height * bitmapData.Stride);
        pBits -= (bitmapData.Stride * (1 + dwLinesRead));

        DWORD dwDestOffset  = 0;
        for (BYTE *pCurLine = pBits; dwDestOffset < dwNumLineBytesInBuffer; pCurLine -= bitmapData.Stride, dwLinesRead++)
        {
            _Analysis_assume_(dwDestOffset + iScanline <= BUFFER_SIZE);
            memcpy(pBuffer + dwDestOffset, pCurLine, iScanline);
            dwDestOffset   += iScanline;
        }

        hr = pOutputStream->Write(pBuffer, dwNumLineBytesInBuffer, &cbWritten);

        //
        // We should check cbWritten here!
        //

        dwTotalBytesRead+= dwNumLineBytesInBuffer;

    }

    //
    // Update the pulBytesWrittenToOutputStream even in failure case
    //
    if (pulBytesWrittenToOutputStream)
    {
        *pulBytesWrittenToOutputStream = (ULONG64)dwTotalBytesRead;
    }

    if (bBitsLocked)
    {
        //
        // Although we do not save the results we should log any errors
        // during UnlockBits
        //
        pTargetBitmap->UnlockBits(&bitmapData);
    }

    if (pBuffer)
    {
        LocalFree(pBuffer);
    }

    return hr;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS