summaryrefslogtreecommitdiff
path: root/wia/ProdScan/FileConv.cpp
diff options
context:
space:
mode:
authorkarlf <[email protected]>2016-08-11 13:28:13 -0700
committerkarlf <[email protected]>2016-08-11 13:28:13 -0700
commit96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch)
treead5f3ede5cbcd6b598677ce41bcf8318471bdd92 /wia/ProdScan/FileConv.cpp
parent687b274aa38fd05c8c26e3068932121876d7f745 (diff)
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'wia/ProdScan/FileConv.cpp')
-rw-r--r--wia/ProdScan/FileConv.cpp730
1 files changed, 730 insertions, 0 deletions
diff --git a/wia/ProdScan/FileConv.cpp b/wia/ProdScan/FileConv.cpp
new file mode 100644
index 00000000..5e3091d2
--- /dev/null
+++ b/wia/ProdScan/FileConv.cpp
@@ -0,0 +1,730 @@
+/**************************************************************************
+*
+* Copyright � Microsoft Corporation
+*
+* Title: FileConv.cpp
+*
+* Description: This file contains implementation of utility functions for
+* image file format conversions used by the sample driver.
+*
+***************************************************************************/
+
+#include "stdafx.h"
+
+//
+// The GDI+ codec name used for the DIB file format:
+//
+#define GDIPLUS_BMP_ENCODER L"image/bmp"
+
+/**************************************************************************\
+*
+* Inline function to convert a GDI+ result code to a COM HRESULT,
+* similar to the HRESULT_FOM_WIN32 macro.
+*
+* Parameters:
+*
+* status - GDI+ return code value
+*
+* Return Value:
+*
+* HRESULT describing the GDI+ status, E_FAIL if conversion is possible
+*
+\**************************************************************************/
+
+inline HRESULT
+GDISTATUS_TO_HRESULT(
+ Gdiplus::Status status)
+{
+ HRESULT hr = E_FAIL;
+ DWORD dwErr = NO_ERROR;
+
+ switch (status)
+ {
+ case Gdiplus::Ok:
+ hr = S_OK;
+ break;
+
+ case Gdiplus::InvalidParameter:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::InvalidParameter"));
+ hr = E_INVALIDARG;
+ break;
+
+ case Gdiplus::OutOfMemory:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::OutOfMemory"));
+ hr = E_OUTOFMEMORY;
+ break;
+
+ case Gdiplus::InsufficientBuffer:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::InsufficientBuffer"));
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ break;
+
+ case Gdiplus::Aborted:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::Aborted"));
+ hr = E_ABORT;
+ break;
+
+ case Gdiplus::ObjectBusy:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::ObjectBusy"));
+ hr = E_PENDING;
+ break;
+
+ case Gdiplus::FileNotFound:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FileNotFound"));
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ break;
+
+ case Gdiplus::AccessDenied:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::AccessDenied"));
+ hr = E_ACCESSDENIED;
+ break;
+
+ case Gdiplus::UnknownImageFormat:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::UnknownImageFormat"));
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_PIXEL_FORMAT);
+ break;
+
+ case Gdiplus::NotImplemented:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::NotImplemented"));
+ hr = E_NOTIMPL;
+ break;
+
+ case Gdiplus::Win32Error:
+ dwErr = GetLastError();
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::Win32Error, last error: 0x%08X", dwErr));
+ hr = HRESULT_FROM_WIN32(dwErr);
+ break;
+
+ case Gdiplus::ValueOverflow:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::ValueOverflow"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::FontFamilyNotFound:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FontFamilyNotFound"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::FontStyleNotFound:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FontFamilyNotFound"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::NotTrueTypeFont:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::NotTrueTypeFont"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::UnsupportedGdiplusVersion:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::UnsupportedGdiplusVersion"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::GdiplusNotInitialized:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::GdiplusNotInitialized"));
+ hr = E_FAIL;
+ break;
+
+ case Gdiplus::WrongState:
+ WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::WrongState"));
+ hr = E_FAIL;
+ break;
+
+ default:
+ WIAEX_ERROR((g_hInst, "GDI+: unknown Gdiplus status code (%u)", (ULONG)status));
+ hr = E_FAIL;
+ }
+
+ return hr;
+}
+
+/**************************************************************************\
+*
+* Executes GdiplusStartup to initialize the GDI+ engine. Must be called
+* before calling ConvertImageToDIB. A matching ShutdownGDIPlus call
+* must be always made to stop the GDI+ engine started by this function.
+*
+* Parameters:
+*
+* ppToken - token returned by GDI+, must be used when calling ShutdownGDIPlus
+*
+* Return Value:
+*
+* S_OK if successful, an error HRESULT otherwise
+*
+\**************************************************************************/
+
+HRESULT
+InitializeGDIPlus(
+ _Out_ ULONG_PTR *ppToken)
+{
+ HRESULT hr = S_OK;
+ GdiplusStartupInput gdiplusStartupInput;
+
+ if (!ppToken)
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
+ }
+
+ //
+ // Start the GDI+ engine:
+ //
+ if (SUCCEEDED(hr))
+ {
+ hr = GDISTATUS_TO_HRESULT(GdiplusStartup(ppToken, &gdiplusStartupInput, NULL));
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "Gdiplus::GdiplusStartup failed, hr = 0x%08X", hr));
+ }
+ }
+
+ return hr;
+}
+
+/**************************************************************************\
+*
+* Executes GdiplusShutdown to shutdown the GDI+ engine.
+*
+* Parameters:
+*
+* pToken - token obtained from a previous InitializeGDIPlus call
+*
+* Return Value:
+*
+* E_INVALIDARG if called with a NULL pToken parameter or S_OK
+* (GDI+ does not return a result code for GdiplusShutdown)
+*
+\**************************************************************************/
+
+HRESULT
+ShutdownGDIPlus(
+ _In_ ULONG_PTR pToken)
+{
+ HRESULT hr = S_OK;
+
+ if (!pToken)
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
+ }
+
+ //
+ // Shutdown the GDI+ engine:
+ //
+ if (SUCCEEDED(hr))
+ {
+ GdiplusShutdown(pToken);
+ }
+
+ return hr;
+}
+
+/**************************************************************************\
+*
+* Internal helper for ConvertImageToDIB. Enumerates available GDI+ image
+* format encoders and returns the CLSID of the specified encoder, if available.
+*
+* Parameters:
+*
+* wszFormat - GDI+ format name, e.g. "image/bmp" for DIB
+* pClisid - returns the CLSID of the GDI+ encoder
+*
+* Return Value:
+*
+* S_OK if successful, an error HRESULT otherwise
+*
+\**************************************************************************/
+
+HRESULT
+_GetEncoderCLSID(
+ _In_ LPCWSTR wszFormat,
+ _Out_ CLSID *pClsid)
+{
+ HRESULT hr = S_OK;
+ UINT nNumEncoders = 0;
+ UINT cbEncoderSize = 0;
+ ImageCodecInfo *pImageCodecInfo = NULL;
+
+ if ((!wszFormat) || (!pClsid))
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = GDISTATUS_TO_HRESULT(GetImageEncodersSize(&nNumEncoders, &cbEncoderSize));
+ if (SUCCEEDED(hr) && (!cbEncoderSize))
+ {
+ hr = E_FAIL;
+ }
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "Gdiplus::GetImageEncodersSize(%ws) failed, hr = 0x%08X", wszFormat, hr));
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ pImageCodecInfo = (ImageCodecInfo*)new BYTE[cbEncoderSize];
+ if (!pImageCodecInfo)
+ {
+ hr = E_OUTOFMEMORY;
+ WIAEX_ERROR((g_hInst, "Failed to allocate memory for the encoder info, hr = 0x%08X", hr));
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = GDISTATUS_TO_HRESULT(GetImageEncoders(nNumEncoders, cbEncoderSize, pImageCodecInfo));
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "Gdiplus::GetImageEncoders(%u encoders) failed, hr = 0x%08X", nNumEncoders, hr));
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = E_FAIL;
+
+ for (UINT j = 0; j < nNumEncoders; ++j)
+ {
+ _Analysis_assume_(cbEncoderSize >= nNumEncoders * sizeof(ImageCodecInfo));
+ _Analysis_assume_(wcslen(wszFormat) < (cbEncoderSize / sizeof(WCHAR)));
+
+ if (!wcscmp(pImageCodecInfo[j].MimeType, wszFormat))
+ {
+ *pClsid = pImageCodecInfo[j].Clsid;
+ hr = S_OK;
+ break;
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "No %ws encoder found in %u available GDI+ encoders, hr = 0x%08X", wszFormat, nNumEncoders, hr));
+ }
+ }
+
+ if (pImageCodecInfo)
+ {
+ delete[] pImageCodecInfo;
+ }
+
+ return hr;
+}
+
+/**************************************************************************\
+*
+* Converts a GDI+ compatible image to a Windows DIB.
+*
+* Parameters:
+*
+* pInputImage - GDI+ Image object containing the image to be converted
+* ppOutputStream - returns a new global memory IStream containing the
+* converted DIB image file (must be released by caller)
+* plImageWidth - (optional) returns the width of the image, in pixels
+* plImageHeight - (optional) returns the height of the image, in pixels
+* plOutputImageBPL - (optional) returns the estimated number of bytes
+* per line for the converted DIB image
+*
+* Remarks:
+*
+* The caller is responsible to release the returned IStream object to
+* free the memory after successful execution of this function.
+*
+* The caller must execute InitializeGDIPlus before calling this function.
+*
+* Return Value:
+*
+* S_OK if successful, an error HRESULT otherwise
+*
+\**************************************************************************/
+
+HRESULT
+ConvertImageToDIB(
+ _In_ Image *pInputImage,
+ _Outptr_ IStream **ppOutputStream,
+ _Out_opt_ LONG *plImageWidth,
+ _Out_opt_ LONG *plImageHeight,
+ _Out_opt_ LONG *plOutputImageBPL)
+{
+ HRESULT hr = S_OK;
+ CLSID clsidBmpEncoder = {};
+ LONG lImageWidth = 0;
+ LONG lImageHeight = 0;
+ LONG lOutputBPL = 0;
+ LONG lBitDepth = 0;
+
+ WIAEX_TRACE_BEGIN;
+
+ if ((!pInputImage) || (!ppOutputStream))
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
+ }
+
+ //
+ // Read the dimensions of the input image:
+ //
+ if (SUCCEEDED(hr))
+ {
+ *ppOutputStream = NULL;
+
+ lImageWidth = pInputImage->GetWidth();
+ lImageHeight = pInputImage->GetHeight();
+ lBitDepth = GetPixelFormatSize(pInputImage->GetPixelFormat());
+
+ if ((lImageWidth > 0) && (lImageHeight > 0) && (lBitDepth > 0))
+ {
+ lOutputBPL = BytesPerLine(lImageWidth, lBitDepth);
+
+ WIAS_TRACE((g_hInst, "Input image is %u x %u pixels, %u bpp, %u BPL (estimated) on output",
+ lImageWidth, lImageHeight, lBitDepth, lOutputBPL));
+ }
+ else
+ {
+ hr = E_FAIL;
+ WIAEX_ERROR((g_hInst, "Incorrect image dimensions reported by GDI+ (%d x %d pixels, %d bpp), hr = 0x%08X",
+ lImageWidth, lImageHeight, lBitDepth, hr));
+ }
+ }
+
+ //
+ // Retrieve the GDI+ encoder necessary to convert the input image to a DIB:
+ //
+ if (SUCCEEDED(hr))
+ {
+ hr = _GetEncoderCLSID(GDIPLUS_BMP_ENCODER, &clsidBmpEncoder);
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "The GDI+ %ws encoder appears to be missing or improperly installed, hr = 0x%08X",
+ GDIPLUS_BMP_ENCODER, hr));
+ }
+ }
+
+ //
+ // Create the output stream in global memory:
+ //
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateStreamOnHGlobal(NULL, TRUE, ppOutputStream);
+ if (SUCCEEDED(hr) && (!(*ppOutputStream)))
+ {
+ hr = E_FAIL;
+ }
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr));
+ }
+ }
+
+ //
+ // Convert and save the image stored in the Image object to the output stream as a DIB:
+ //
+ if (SUCCEEDED(hr))
+ {
+ hr = GDISTATUS_TO_HRESULT(pInputImage->Save(*ppOutputStream, &clsidBmpEncoder));
+ if (FAILED(hr))
+ {
+ WIAEX_ERROR((g_hInst, "Image::Save(%ws) failed, hr = 0x%08X", GDIPLUS_BMP_ENCODER, hr));
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (ppOutputStream && *ppOutputStream)
+ {
+ (*ppOutputStream)->Release();
+ *ppOutputStream = NULL;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (plImageWidth)
+ {
+ *plImageWidth = lImageWidth;
+ }
+ if (plImageHeight)
+ {
+ *plImageHeight = lImageHeight;
+ }
+ if (plOutputImageBPL)
+ {
+ *plOutputImageBPL = lOutputBPL;
+ }
+ }
+
+ WIAEX_TRACE_FUNC_HR;
+
+ return hr;
+}
+
+/**************************************************************************\
+*
+* Converts a 8-bpp grayscale or 24-bpp RGB color DIB to a WIA Raw image.
+*
+* Parameters:
+*
+* ppInputStream - input stream containing the DIB to be converted
+* ppOutputStream - returns a new global memory IStream containing the
+* converted Raw image file (must be released by caller)
+*
+* Remarks:
+*
+* The current form of this function for simplicty supports only 8-bpp
+* Grayscale and 24-bpp RGB color images. Palettes are not supported.
+*
+* The caller is responsible to release the returned IStream object to
+* free the memory after successful execution of this function.
+*
+* Return Value:
+*
+* S_OK if successful, an error HRESULT otherwise
+*
+\**************************************************************************/
+
+HRESULT
+ConvertDibToRaw(
+ _In_ IStream *pInputStream,
+ _Out_ IStream **ppOutputStream)
+{
+ HRESULT hr = S_OK;
+ LARGE_INTEGER liOffset = {};
+ WIA_RAW_HEADER wiaRawHeader = {};
+ BYTE bGrayPalette[256] = {};
+ BITMAPINFOHEADER bih = {};
+ ULONG ulDataSize = 0;
+ ULONG ulDataWritten = 0;
+ ULONG ulPaletteSize = 0;
+
+ WIAEX_TRACE_BEGIN;
+
+ if ((!pInputStream) || (!ppOutputStream))
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08.8X", hr));
+ }
+ else
+ {
+ *ppOutputStream = NULL;
+ }
+
+ liOffset.LowPart = sizeof(BITMAPFILEHEADER);
+ hr = pInputStream->Seek(liOffset, STREAM_SEEK_SET, NULL);
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::Seek(%u, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", liOffset.LowPart, hr));
+ }
+
+ if (S_OK == hr)
+ {
+ //
+ // Extract the DIB header from the input stream:
+ //
+ hr = pInputStream->Read((void *)&bih, sizeof(bih), &ulDataSize);
+ if ((S_OK == hr) && (ulDataSize != sizeof(bih)))
+ {
+ hr = E_FAIL;
+ WIAEX_ERROR((g_hInst, "Expected to read %u bytes for the DIB header, got %u bytes, hr = 0x%08X",
+ sizeof(bih), ulDataSize, hr));
+ }
+
+ //
+ // Validate the input DIB and fill in the output Raw header:
+ //
+ if (S_OK == hr)
+ {
+ if ((bih.biBitCount != 24) && (bih.biBitCount != 8))
+ {
+ hr = E_INVALIDARG;
+ WIAEX_ERROR((g_hInst, "Test image must be either 8-bpp Grayscale or 24-bpp RGB Color, hr = 0x%08X",
+ sizeof(bih), ulDataSize, hr));
+ }
+ else
+ {
+ const char szRawSignature[] = "WRAW";
+ memcpy(&wiaRawHeader.Tag, szRawSignature, sizeof(DWORD));
+
+ wiaRawHeader.Version = 0x00010000;
+ wiaRawHeader.HeaderSize = sizeof(wiaRawHeader);
+
+ wiaRawHeader.XExtent = bih.biWidth;
+ wiaRawHeader.YExtent = bih.biHeight;
+ wiaRawHeader.LineOrder = (bih.biHeight < 0) ? WIA_LINE_ORDER_TOP_TO_BOTTOM : WIA_LINE_ORDER_BOTTOM_TO_TOP;
+ wiaRawHeader.BitsPerPixel = bih.biBitCount;
+ wiaRawHeader.BytesPerLine = BytesPerLine(bih.biWidth, bih.biBitCount);
+ wiaRawHeader.ChannelsPerPixel = (8 == bih.biBitCount) ? 1 : 3;
+ wiaRawHeader.DataType = (8 == bih.biBitCount) ? WIA_DATA_GRAYSCALE : WIA_DATA_RAW_BGR;
+ wiaRawHeader.BitsPerChannel[0] = 8;
+ wiaRawHeader.BitsPerChannel[1] = (8 == bih.biBitCount) ? 0 : 8;
+ wiaRawHeader.BitsPerChannel[2] = (8 == bih.biBitCount) ? 0 : 8;
+ wiaRawHeader.Compression = WIA_COMPRESSION_NONE;
+ wiaRawHeader.PhotometricInterp = WIA_PHOTO_WHITE_1;
+
+ //
+ // The scan resolution is fixed for this sample driver:
+ //
+ wiaRawHeader.XRes = OPTICAL_RESOLUTION;
+ wiaRawHeader.YRes = OPTICAL_RESOLUTION;
+
+ ulDataSize = wiaRawHeader.BytesPerLine * wiaRawHeader.YExtent;
+ ulPaletteSize = (8 == bih.biBitCount) ? (256 * sizeof(BYTE)) : 0;
+
+ wiaRawHeader.RawDataSize = ulDataSize;
+ wiaRawHeader.RawDataOffset = ulPaletteSize;
+ wiaRawHeader.PaletteOffset = 0;
+ wiaRawHeader.PaletteSize = ulPaletteSize;
+
+ //
+ // For 8-bpp Grayscale data prepare a standard grayscale palette with entries sorted
+ // in increasing or decreasing order depending on the photometric interpretation:
+ //
+ if (8 == bih.biBitCount)
+ {
+ for (UINT i = 0; i < 256; i++)
+ {
+ bGrayPalette[i] = (WIA_PHOTO_WHITE_1 == wiaRawHeader.PhotometricInterp) ? (BYTE)i : (255 - (BYTE)i);
+ }
+ }
+
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.Version = 0x%08X", wiaRawHeader.Version));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.HeaderSize = %u bytes", wiaRawHeader.HeaderSize));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.XExtent = %u pixels", wiaRawHeader.XExtent));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.YExtent = %u pixels", wiaRawHeader.YExtent));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.LineOrder = %u", wiaRawHeader.LineOrder));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerPixel = %u bpp", wiaRawHeader.BitsPerPixel));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BytesPerLine = %u BPL", wiaRawHeader.BytesPerLine));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.ChannelsPerPixel = %u", wiaRawHeader.ChannelsPerPixel));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.DataType = %u", wiaRawHeader.DataType));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[0] = %u bps", wiaRawHeader.BitsPerChannel[0]));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[1] = %u bps", wiaRawHeader.BitsPerChannel[1]));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[2] = %u bps", wiaRawHeader.BitsPerChannel[2]));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.Compression = %u", wiaRawHeader.Compression));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PhotometricInterp = %u", wiaRawHeader.PhotometricInterp));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.XRes = %u DPI", wiaRawHeader.XRes));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.YRes = %u DPI", wiaRawHeader.YRes));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.RawDataOffset = %u bytes", wiaRawHeader.RawDataOffset));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.RawDataSize = %u bytes", wiaRawHeader.RawDataSize));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PaletteOffset = %u bytes", wiaRawHeader.PaletteOffset));
+ WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PaletteSize = %u bytes", wiaRawHeader.PaletteSize));
+ }
+ }
+ else
+ {
+ WIAEX_ERROR((g_hInst, "Failed to read the DIB header for the test image, hr = 0x%08X", hr));
+ }
+
+ //
+ // If there is a grayscale palette, jump the input stream pointer past it:
+ //
+ if ((S_OK == hr) && (8 == bih.biBitCount))
+ {
+ liOffset.LowPart = 256 * sizeof(RGBQUAD);
+ hr = pInputStream->Seek(liOffset, STREAM_SEEK_CUR, NULL);
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::Seek(%u, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", liOffset.LowPart, hr));
+ }
+ }
+
+ //
+ // Create the output stream in memory:
+ //
+ if (S_OK == hr)
+ {
+ hr = CreateStreamOnHGlobal(NULL, TRUE, ppOutputStream);
+ if (SUCCEEDED(hr) && (!(*ppOutputStream)))
+ {
+ hr = E_FAIL;
+ }
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr));
+ }
+ }
+
+ //
+ // Write the Raw header to the output stream:
+ //
+ if (S_OK == hr)
+ {
+ hr = (*ppOutputStream)->Write(&wiaRawHeader, sizeof(wiaRawHeader), &ulDataWritten);
+ if (SUCCEEDED(hr) && (sizeof(wiaRawHeader) != ulDataWritten))
+ {
+ hr = E_FAIL;
+ WIAEX_ERROR((g_hInst, "Expected to write %u bytes for the raw header, wrote %u bytes, hr = 0x%08X",
+ sizeof(wiaRawHeader), ulDataWritten, hr));
+ }
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::Write(%u bytes) failed, hr = 0x%08X", sizeof(wiaRawHeader), hr));
+ }
+ }
+
+ //
+ // Write the palette (if one) to the output stream:
+ //
+ if ((S_OK == hr) && (8 == bih.biBitCount))
+ {
+ hr = (*ppOutputStream)->Write(&bGrayPalette[0], ulPaletteSize, &ulDataWritten);
+ if (SUCCEEDED(hr) && (ulPaletteSize != ulDataWritten))
+ {
+ hr = E_FAIL;
+ WIAEX_ERROR((g_hInst, "Expected to write %u bytes for the raw palette, wrote %u bytes, hr = 0x%08X",
+ ulPaletteSize, ulDataWritten, hr));
+ }
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::Write(%u bytes) failed, hr = 0x%08X", ulPaletteSize, hr));
+ }
+ }
+
+ //
+ // Write the Raw image data to the output stream:
+ //
+ if (S_OK == hr)
+ {
+ ULARGE_INTEGER uliDataSize = {}, uliRead = {}, uliWritten = {};
+
+ uliDataSize.LowPart = ulDataSize;
+
+ hr = pInputStream->CopyTo(*ppOutputStream, uliDataSize, &uliRead, &uliWritten);
+ if ((S_OK == hr) && ((ulDataSize != uliRead.LowPart) || (ulDataSize != uliWritten.LowPart)))
+ {
+ hr = E_FAIL;
+ WIAEX_ERROR((g_hInst, "Expected to stream copy %u bytes for the raw image data, copied %u bytes, hr = 0x%08X",
+ ulDataSize, uliWritten.LowPart, hr));
+ }
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::CopyTo(%u bytes) failed, hr = 0x%08X", ulDataSize, hr));
+ }
+ }
+
+ //
+ // Reset the output stream seek pointer at the beginning of the stream:
+ //
+ if (S_OK == hr)
+ {
+ liOffset.LowPart = 0;
+ hr = (*ppOutputStream)->Seek(liOffset, STREAM_SEEK_SET, NULL);
+ if (S_OK != hr)
+ {
+ WIAEX_ERROR((g_hInst, "IStream::Seek(0, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", hr));
+ }
+ }
+ }
+
+ if ((S_OK != hr) && ppOutputStream && *ppOutputStream)
+ {
+ (*ppOutputStream)->Release();
+ *ppOutputStream = NULL;
+ }
+
+ WIAEX_TRACE_FUNC_HR;
+
+ return hr;
+}