1125 lines
35 KiB
C++
1125 lines
35 KiB
C++
//
|
|
// loadimag.cpp
|
|
//
|
|
// implementation of loading a file from disk via an installed graphic filter
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "pbrush.h"
|
|
#include "imgwnd.h"
|
|
#include "imgsuprt.h"
|
|
#include "loadimag.h"
|
|
#include "bmpstrm.h"
|
|
#include "imaging.h"
|
|
|
|
#include <atlbase.h>
|
|
|
|
// must define one of the following:
|
|
//#define _USE_FLT_API
|
|
#ifdef _X86_
|
|
#define _USE_IFL_API
|
|
#endif
|
|
|
|
#ifdef _USE_FLT_API
|
|
#include "filtapi.h"
|
|
#endif
|
|
|
|
#ifdef _USE_IFL_API
|
|
#include "image.h"
|
|
#include "interlac.h"
|
|
#define MAX_PAL_SIZE 256
|
|
|
|
#ifdef PNG_SUPPORT // for Portable Network Graphics. As of 12/10/1996 the support was broken
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Places a line of image data from an ADAM 7 interlaced file (i.e., currently
|
|
// a PNG file) into its correct position in a memory buffer: this memory
|
|
// buffer is essentially an array of pointers to the rows of the image in
|
|
// which the pixel data is to be set.
|
|
//----------------------------------------------------------------------------
|
|
IFLERROR ReadADAM7InterlacedImage(LPBYTE apbImageBuffer[], IFLHANDLE pfpbFROM,
|
|
int ImageHeight, int ImageWidth, int cbPixelSize,
|
|
IFLCLASS ImageClass)
|
|
{
|
|
|
|
|
|
int cRasterLines = iflGetRasterLineCount(pfpbFROM);
|
|
|
|
ADAM7_STRUCT stAdam7;
|
|
stAdam7.iImageHeight = ImageHeight;
|
|
stAdam7.iImageWidth = ImageWidth;
|
|
stAdam7.Class = ImageClass;
|
|
stAdam7.cbPixelSize = iflGetBitsPerPixel (pfpbFROM)/8;//cbPixelSize;
|
|
stAdam7.iPassLine = 0;
|
|
LPBYTE pbScanLine = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, ImageWidth * stAdam7.cbPixelSize);
|
|
wsprintf (buf, TEXT("Pixel size: %d, Size of a scan line: %d\n"), stAdam7.cbPixelSize,
|
|
ImageWidth*stAdam7.cbPixelSize);
|
|
|
|
if (pbScanLine == NULL)
|
|
return IFLERR_MEMORY;
|
|
|
|
int cTotalScanLines = iADAM7CalculateNumberOfScanLines(&stAdam7);
|
|
|
|
int iLine;
|
|
IFLERROR idErr;
|
|
BOOL fEmptyLine;
|
|
|
|
for (iLine = 0, idErr = IFLERR_NONE, fEmptyLine = FALSE;
|
|
idErr == IFLERR_NONE && iLine < (int)cRasterLines;
|
|
iLine++)
|
|
{
|
|
if (!fEmptyLine)
|
|
idErr = iflRead(pfpbFROM, pbScanLine, 1);
|
|
|
|
stAdam7.iScanLine = iLine;
|
|
fEmptyLine = ADAM7AddRowToImageBuffer(apbImageBuffer, pbScanLine, &stAdam7);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, pbScanLine);
|
|
return idErr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Deallocates the image space allocated in the function AllocateImageSpace()
|
|
//----------------------------------------------------------------------------
|
|
LPBYTE *FreeImageSpace(HANDLE hHeap, LPBYTE ppImageSpace[], int height)
|
|
{
|
|
if (ppImageSpace != NULL)
|
|
{
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
if (ppImageSpace[i] != NULL)
|
|
{
|
|
HeapFree(hHeap, 0, ppImageSpace[i]);
|
|
ppImageSpace[i] = NULL;
|
|
}
|
|
}
|
|
|
|
HeapFree(hHeap, 0, ppImageSpace);
|
|
ppImageSpace = NULL;
|
|
}
|
|
|
|
return ppImageSpace;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Allocate some image space: this function will create a dynamic array
|
|
// of "height" pointers which each point to an allocated row of bytes of
|
|
// size "width".
|
|
//----------------------------------------------------------------------------
|
|
LPBYTE *AllocateImageSpace(HANDLE hHeap, int height, int width, int cbSize)
|
|
{
|
|
LPBYTE *ppImageSpace = (LPBYTE *)HeapAlloc(hHeap, 0, height * sizeof(void *));
|
|
TCHAR buf[200];
|
|
wsprintf (buf, TEXT("Size of image line: %d\n"), width*cbSize);
|
|
|
|
|
|
if (ppImageSpace != NULL)
|
|
{
|
|
// Init the pointers to NULL: this makes error recovery easier
|
|
for (int i = 0; i < height; i++)
|
|
ppImageSpace[i] = NULL;
|
|
|
|
// NOW allocate the pointer space for the image
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
ppImageSpace[i] = (LPBYTE)HeapAlloc(hHeap, 0, width * cbSize);
|
|
if (ppImageSpace[i] == NULL)
|
|
break;
|
|
}
|
|
|
|
if (i < height) // We weren't able to allocate the required space
|
|
ppImageSpace = FreeImageSpace(hHeap, ppImageSpace, height);
|
|
}
|
|
|
|
return ppImageSpace;
|
|
}
|
|
#endif // PNG_SUPPORT
|
|
|
|
#endif // _USE_IFL_API
|
|
|
|
|
|
|
|
// returns a pointer to the extension of a file.
|
|
//
|
|
// in:
|
|
// qualified or unqualfied file name
|
|
//
|
|
// returns:
|
|
// pointer to the extension of this file. if there is no extension
|
|
// as in "foo" we return a pointer to the NULL at the end
|
|
// of the file
|
|
//
|
|
// foo.txt ==> ".txt"
|
|
// foo ==> ""
|
|
// foo. ==> "."
|
|
//
|
|
|
|
LPCTSTR FindExtension(LPCTSTR pszPath)
|
|
{
|
|
for (LPCTSTR pszDot = NULL; *pszPath; pszPath = CharNext(pszPath))
|
|
{
|
|
switch (*pszPath)
|
|
{
|
|
case TEXT('.'):
|
|
pszDot = pszPath; // remember the last dot
|
|
break;
|
|
case TEXT('\\'):
|
|
case TEXT(' '): // extensions can't have spaces
|
|
pszDot = NULL; // forget last dot, it was in a directory
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we found the extension, return ptr to the dot, else
|
|
// ptr to end of the string (NULL extension)
|
|
return pszDot ? pszDot : pszPath;
|
|
}
|
|
|
|
//
|
|
// GetFilterInfo
|
|
//
|
|
// 32-bit import filters are listed in the registry...
|
|
//
|
|
// HKLM\SOFTWARE\Microsoft\Shared Tools\Graphics Filters\Import\XXX
|
|
// Path = filename
|
|
// Name = friendly name
|
|
// Extenstions = file extenstion list
|
|
//
|
|
#pragma data_seg(".text")
|
|
static const TCHAR c_szImpHandlerKey[] = TEXT("SOFTWARE\\Microsoft\\Shared Tools\\Graphics Filters\\Import");
|
|
static const TCHAR c_szExpHandlerKey[] = TEXT("SOFTWARE\\Microsoft\\Shared Tools\\Graphics Filters\\Export");
|
|
static const TCHAR c_szName[] = TEXT("Name");
|
|
static const TCHAR c_szPath[] = TEXT("Path");
|
|
static const TCHAR c_szExts[] = TEXT("Extensions");
|
|
static const TCHAR c_szImageAPI[] = TEXT("Image API Enabled Filters");
|
|
#pragma data_seg()
|
|
|
|
BOOL GetInstalledFilters(BOOL bOpenFileDialog, int i, LPTSTR szName, UINT cbName,
|
|
LPTSTR szExt, UINT cbExt, LPTSTR szHandler, UINT cbHandler, BOOL& bImageAPI)
|
|
{
|
|
HKEY hkey;
|
|
HKEY hkeyT;
|
|
TCHAR ach[80];
|
|
BOOL rc = FALSE; // return code
|
|
|
|
bImageAPI = FALSE;
|
|
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
bOpenFileDialog ? c_szImpHandlerKey : c_szExpHandlerKey, &hkey) == 0)
|
|
{
|
|
if (RegEnumKey(hkey, i, ach, sizeof(ach)/sizeof(ach[0]))==0)
|
|
{
|
|
if (RegOpenKey(hkey, ach, &hkeyT) == 0)
|
|
{
|
|
if (szName)
|
|
{
|
|
szName[0] = 0;
|
|
RegQueryValueEx(hkeyT, c_szName, NULL, NULL,
|
|
(LPBYTE)szName, (LPDWORD)&cbName);
|
|
}
|
|
if (szExt)
|
|
{
|
|
szExt[0] = 0;
|
|
RegQueryValueEx(hkeyT, c_szExts, NULL, NULL,
|
|
(LPBYTE)szExt, (LPDWORD)&cbExt);
|
|
}
|
|
if (szHandler)
|
|
{
|
|
szHandler[0] = 0;
|
|
RegQueryValueEx(hkeyT, c_szPath, NULL, NULL,
|
|
(LPBYTE)szHandler, (LPDWORD)&cbHandler);
|
|
}
|
|
|
|
RegCloseKey(hkeyT);
|
|
rc = TRUE;
|
|
}
|
|
|
|
TCHAR szEnabledFilters[1024];
|
|
DWORD dwEnabledFiltersSize = sizeof(szEnabledFilters);
|
|
|
|
// Does the filter support Image Library Files API ?
|
|
|
|
if (RegQueryValueEx(hkey, c_szImageAPI, NULL, NULL,
|
|
(LPBYTE)szEnabledFilters, &dwEnabledFiltersSize) == 0)
|
|
{
|
|
for (
|
|
LPCTSTR pExt = _tcstok(szEnabledFilters, _T(" "));
|
|
pExt != NULL && bImageAPI != TRUE;
|
|
pExt = _tcstok(NULL, _T(" ")))
|
|
{
|
|
if (_tcsicmp(pExt, ach) == 0)
|
|
{
|
|
bImageAPI = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifdef _USE_FLT_API
|
|
//
|
|
// GetHandlerForFile
|
|
//
|
|
// find an import/export filter for the given file.
|
|
//
|
|
BOOL GetHandlerForFile(BOOL bImport, LPCTSTR szFile, LPTSTR szHandler, UINT cb)
|
|
{
|
|
TCHAR buf[40];
|
|
BOOL rc = FALSE; // return code
|
|
|
|
*szHandler = 0;
|
|
|
|
if (szFile == NULL)
|
|
return FALSE;
|
|
|
|
// find the extension
|
|
LPCTSTR ext = FindExtension(szFile);
|
|
|
|
BOOL bImageAPI;
|
|
|
|
for (int i = 0;
|
|
GetInstalledFilters(bImport, i, NULL, 0, buf, sizeof(buf), szHandler, cb, bImageAPI);
|
|
i++)
|
|
{
|
|
if (lstrcmpi(ext+1, buf) == 0)
|
|
break;
|
|
else
|
|
*szHandler = 0;
|
|
}
|
|
|
|
// make sure the handler file does exist
|
|
if (*szHandler && GetFileAttributes(szHandler) != -1)
|
|
rc = TRUE;
|
|
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// FindBitmapInfo
|
|
//
|
|
// find the DIB bitmap in a memory meta file...
|
|
//
|
|
LPBITMAPINFOHEADER FindBitmapInfo(LPMETAHEADER pmh)
|
|
{
|
|
for (LPMETARECORD pmr = (LPMETARECORD)((LPBYTE)pmh + pmh->mtHeaderSize*2);
|
|
pmr < (LPMETARECORD)((LPBYTE)pmh + pmh->mtSize*2);
|
|
pmr = (LPMETARECORD)((LPBYTE)pmr + pmr->rdSize*2))
|
|
{
|
|
switch (pmr->rdFunction)
|
|
{
|
|
case META_DIBBITBLT:
|
|
return (LPBITMAPINFOHEADER)&(pmr->rdParm[8]);
|
|
|
|
case META_DIBSTRETCHBLT:
|
|
return (LPBITMAPINFOHEADER)&(pmr->rdParm[10]);
|
|
|
|
case META_STRETCHDIB:
|
|
return (LPBITMAPINFOHEADER)&(pmr->rdParm[11]);
|
|
|
|
case META_SETDIBTODEV:
|
|
return (LPBITMAPINFOHEADER)&(pmr->rdParm[9]);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif // _USE_FLT_API
|
|
|
|
#ifdef _USE_IFL_API
|
|
IFLERROR ReadGIFInterlacedImage(BYTE *ppbImageBuffer,
|
|
IFLHANDLE pfpbFROM,
|
|
int ImageHeight, DWORD dwWidthInBytes)
|
|
{
|
|
int iLine, iPass, iIntLine, iTempLine;
|
|
IFLERROR idErr;
|
|
|
|
|
|
WORD InterlaceMultiplier[] = { 8, 8, 4, 2 };
|
|
WORD InterlaceOffset[] = { 0, 4, 2, 1 };
|
|
|
|
idErr = IFLERR_NONE;
|
|
|
|
iPass = 0;
|
|
iIntLine = InterlaceOffset[iPass];
|
|
iLine = 0;
|
|
while (idErr == IFLERR_NONE && iLine < ImageHeight)
|
|
{
|
|
iTempLine = InterlaceMultiplier[iPass] * iIntLine + InterlaceOffset[iPass];
|
|
if (iTempLine >= ImageHeight)
|
|
{
|
|
iPass++;
|
|
iIntLine = 0;
|
|
iTempLine = InterlaceOffset[iPass];
|
|
}
|
|
|
|
if (iTempLine < ImageHeight)
|
|
{
|
|
idErr = iflRead(pfpbFROM,
|
|
(LPBYTE)ppbImageBuffer+((ImageHeight-iTempLine-1)*dwWidthInBytes),
|
|
1);
|
|
iLine++;
|
|
}
|
|
iIntLine++;
|
|
}
|
|
|
|
return idErr;
|
|
}
|
|
#endif // _USE_IFL_API
|
|
|
|
//
|
|
// LoadDIBFromFile
|
|
//
|
|
// load a image file using a image import filter. The filters use ANSI strings.
|
|
//
|
|
|
|
HGLOBAL LoadDIBFromFileA(LPCSTR szFileName, GUID *pguidFltTypeUsed)
|
|
{
|
|
#ifdef _USE_IFL_API
|
|
|
|
IFLTYPE iflType;
|
|
|
|
iflImageType((LPSTR)szFileName, &iflType);
|
|
|
|
// make sure the image is of a type we know how to import
|
|
if (iflType == IFLT_PNG)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
IFLHANDLE iflHandle = iflCreateReadHandle(iflType);
|
|
if (!iflHandle)
|
|
{
|
|
//
|
|
// No filter installed for this type
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
LPBYTE lpStart = 0;
|
|
|
|
__try
|
|
{
|
|
|
|
IFLERROR iflErr = iflOpen(iflHandle, (LPSTR)szFileName, IFLM_READ);
|
|
if (iflErr != IFLERR_NONE)
|
|
{
|
|
iflFreeHandle(iflHandle);
|
|
return NULL;
|
|
}
|
|
|
|
ASSERT(pguidFltTypeUsed);
|
|
|
|
switch (iflType)
|
|
{
|
|
case IFLT_GIF: *pguidFltTypeUsed = WiaImgFmt_GIF; break;
|
|
case IFLT_BMP: *pguidFltTypeUsed = WiaImgFmt_BMP; break;
|
|
case IFLT_JPEG: *pguidFltTypeUsed = WiaImgFmt_JPEG; break;
|
|
case IFLT_TIFF: *pguidFltTypeUsed = WiaImgFmt_TIFF; break;
|
|
case IFLT_PNG: *pguidFltTypeUsed = WiaImgFmt_PNG; break;
|
|
case IFLT_PCD: *pguidFltTypeUsed = WiaImgFmt_PHOTOCD; break;
|
|
default: *pguidFltTypeUsed = WiaImgFmt_UNDEFINED; break;
|
|
}
|
|
|
|
IFLCLASS iflClass = iflGetClass(iflHandle);
|
|
IFLSEQUENCE iflSequence = iflGetSequence(iflHandle);
|
|
IFLCOMPRESSION iflCompression = iflGetCompression(iflHandle);
|
|
WORD iBPS = (WORD) iflGetBitsPerChannel(iflHandle);
|
|
|
|
if (iflClass != IFLCL_RGB && iflClass != IFLCL_PALETTE &&
|
|
iflClass != IFLCL_GRAY && iflClass != IFLCL_BILEVEL)
|
|
{
|
|
#ifdef _DEBUG
|
|
TRACE(TEXT("LoadDIBFromFile: Not a RGB/PALETTE/GRAY/BW image.\n"));
|
|
MessageBox (NULL, TEXT("Not a RGB/PALETTE/GRAY/BW image."),
|
|
TEXT("Loadimag.cpp"), MB_OK);
|
|
#endif
|
|
iflClose(iflHandle);
|
|
iflFreeHandle(iflHandle);
|
|
return NULL;
|
|
}
|
|
|
|
// get the transparent color
|
|
if (iflClass == IFLCL_RGB)
|
|
{
|
|
IFLCOLOR iflTransColor;
|
|
g_bUseTrans = (IFLERR_NONE ==
|
|
iflControl(iflHandle, IFLCMD_TRANS_RGB, 0, 0, &iflTransColor));
|
|
if (g_bUseTrans)
|
|
crTrans = RGB(iflTransColor.wRed,
|
|
iflTransColor.wGreen,
|
|
iflTransColor.wBlue);
|
|
}
|
|
else // must be IFLCL_PALETTE or IFLCL_GRAY or IFLCL_BILEVEL
|
|
{
|
|
BYTE byTransIdx;
|
|
g_bUseTrans = (IFLERR_NONE ==
|
|
iflControl(iflHandle, IFLCMD_TRANS_IDX, 0, 0, &byTransIdx));
|
|
if (g_bUseTrans)
|
|
crTrans = byTransIdx; // need to convert to COLORREF below
|
|
}
|
|
|
|
BITMAPINFOHEADER bi;
|
|
memset(&bi, 0, sizeof(BITMAPINFOHEADER));
|
|
|
|
bi.biSize = sizeof(BITMAPINFOHEADER); // should be 0x28 or 40 decimal
|
|
bi.biWidth = iflGetWidth(iflHandle);
|
|
bi.biHeight = iflGetHeight(iflHandle);
|
|
bi.biPlanes = 1;
|
|
|
|
|
|
|
|
|
|
if (iflClass == IFLCL_RGB)
|
|
{
|
|
#ifdef PNG_SUPPORT
|
|
if (iflType == IFLT_PNG)
|
|
{
|
|
bi.biBitCount = iBPS*3;
|
|
}
|
|
else
|
|
#endif // PNG_SUPPORT
|
|
{
|
|
bi.biBitCount = (WORD) iflGetBitsPerPixel (iflHandle);
|
|
}
|
|
}
|
|
else // must be IFLCL_PALETTE or IFLCL_GRAY or IFLCL_BILEVEL
|
|
{
|
|
bi.biBitCount = 8;
|
|
}
|
|
|
|
|
|
|
|
bi.biCompression = 0;
|
|
// convert width in pixels to bytes after rounding it up first
|
|
DWORD dwWidthInBytes = ((bi.biWidth * bi.biBitCount + 31) & ~31)/8;
|
|
bi.biSizeImage = abs(bi.biHeight) * dwWidthInBytes;
|
|
// bi.biXPelsPerMeter = 0;
|
|
// bi.biYPelsPerMeter = 0;
|
|
if (iflClass == IFLCL_PALETTE || iflClass == IFLCL_GRAY
|
|
|| iflClass == IFLCL_BILEVEL)
|
|
bi.biClrUsed = MAX_PAL_SIZE;
|
|
// bi.biClrImportant = 0;
|
|
|
|
LPBYTE lpBMP;
|
|
|
|
if ((lpBMP = lpStart = (LPBYTE) GlobalAlloc(GMEM_FIXED,
|
|
bi.biSize + bi.biClrUsed*sizeof(RGBQUAD) + bi.biSizeImage)) == NULL)
|
|
goto exit;
|
|
|
|
memcpy(lpBMP, &bi, bi.biSize);
|
|
lpBMP += bi.biSize;
|
|
|
|
BYTE byTemp;
|
|
int i, j;
|
|
|
|
switch (iflSequence)
|
|
{
|
|
case IFLSEQ_TOPDOWN:
|
|
switch (iflClass)
|
|
{
|
|
case IFLCL_RGB:
|
|
|
|
lpBMP += bi.biClrUsed*sizeof(RGBQUAD) + bi.biSizeImage -
|
|
dwWidthInBytes;
|
|
for (i = 0; i < abs(bi.biHeight); lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
// need to swap RED with BLUE for internal DIB display
|
|
for (j = 0; j < bi.biWidth*3; j+=3)
|
|
{
|
|
byTemp = *(lpBMP+j);
|
|
*(lpBMP+j) = *(lpBMP+j+2);
|
|
*(lpBMP+j+2) = byTemp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IFLCL_PALETTE:
|
|
|
|
// get palette info first...
|
|
RGBTRIPLE Pal3[MAX_PAL_SIZE];
|
|
RGBQUAD Pal4[MAX_PAL_SIZE];
|
|
ZeroMemory (Pal3, MAX_PAL_SIZE*(sizeof(RGBTRIPLE)));
|
|
iflErr = iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &Pal3);
|
|
|
|
for (i = 0; i < MAX_PAL_SIZE; i++)
|
|
{
|
|
Pal4[i].rgbBlue = Pal3[i].rgbtRed;
|
|
Pal4[i].rgbGreen = Pal3[i].rgbtGreen;
|
|
Pal4[i].rgbRed = Pal3[i].rgbtBlue;
|
|
Pal4[i].rgbReserved = 0;
|
|
}
|
|
memcpy(lpBMP, Pal4, sizeof(Pal4));
|
|
|
|
if (g_bUseTrans)
|
|
// convert the transparent color index to COLORREF
|
|
crTrans = RGB(Pal4[crTrans].rgbRed,Pal4[crTrans].rgbGreen,
|
|
Pal4[crTrans].rgbBlue);
|
|
|
|
lpBMP += sizeof(Pal4) + bi.biSizeImage - dwWidthInBytes;
|
|
|
|
for (i = 0;i < abs(bi.biHeight);lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
}
|
|
|
|
break;
|
|
|
|
case IFLCL_GRAY:
|
|
|
|
// get palette info first...
|
|
//BYTE PalGray[MAX_PAL_SIZE];
|
|
//iflErr = iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &PalGray);
|
|
|
|
for (i = 0; i < MAX_PAL_SIZE; i++)
|
|
{
|
|
Pal4[i].rgbBlue = (BYTE) i;//PalGray[i];
|
|
Pal4[i].rgbGreen = (BYTE) i;//PalGray[i];
|
|
Pal4[i].rgbRed = (BYTE) i;//PalGray[i];
|
|
Pal4[i].rgbReserved = 0;
|
|
}
|
|
memcpy(lpBMP, Pal4, sizeof(Pal4));
|
|
|
|
if (g_bUseTrans)
|
|
// convert the transparent color index to COLORREF
|
|
crTrans = RGB(Pal4[crTrans].rgbRed, Pal4[crTrans].rgbGreen,
|
|
Pal4[crTrans].rgbBlue);
|
|
|
|
lpBMP += sizeof(Pal4) + bi.biSizeImage - dwWidthInBytes;
|
|
|
|
for (i = 0;i < abs(bi.biHeight);lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
}
|
|
|
|
break;
|
|
|
|
case IFLCL_BILEVEL:
|
|
|
|
// set color Black
|
|
Pal4[0].rgbBlue = 0;
|
|
Pal4[0].rgbGreen = 0;
|
|
Pal4[0].rgbRed = 0;
|
|
Pal4[0].rgbReserved = 0;
|
|
|
|
// set color White
|
|
Pal4[1].rgbBlue = 255;
|
|
Pal4[1].rgbGreen = 255;
|
|
Pal4[1].rgbRed = 255;
|
|
Pal4[1].rgbReserved = 0;
|
|
|
|
memcpy(lpBMP, Pal4, sizeof(Pal4));
|
|
|
|
if (g_bUseTrans)
|
|
// convert the transparent color index to COLORREF
|
|
crTrans = RGB(Pal4[crTrans].rgbRed,
|
|
Pal4[crTrans].rgbGreen,
|
|
Pal4[crTrans].rgbBlue);
|
|
|
|
lpBMP += sizeof(Pal4) + bi.biSizeImage - dwWidthInBytes;
|
|
|
|
for (i = 0;i < abs(bi.biHeight);lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// currently not supported
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IFLSEQ_BOTTOMUP:
|
|
|
|
lpBMP += bi.biClrUsed*sizeof(RGBQUAD) + bi.biSizeImage - dwWidthInBytes;
|
|
|
|
for (i = 0;i < abs(bi.biHeight);lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
|
|
// need to swap RED with BLUE for internal DIB display
|
|
for (j = 0; j < bi.biWidth*3; j+=3)
|
|
{
|
|
byTemp = *(lpBMP+j);
|
|
*(lpBMP+j) = *(lpBMP+j+2);
|
|
*(lpBMP+j+2) = byTemp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IFLSEQ_GIF_INTERLACED:
|
|
{
|
|
|
|
// get color palette info first...
|
|
RGBTRIPLE Pal3[MAX_PAL_SIZE];
|
|
RGBQUAD Pal4[MAX_PAL_SIZE];
|
|
iflErr = iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &Pal3);
|
|
|
|
for (i = 0; i < MAX_PAL_SIZE; i++)
|
|
{
|
|
Pal4[i].rgbBlue = Pal3[i].rgbtRed;
|
|
Pal4[i].rgbGreen = Pal3[i].rgbtGreen;
|
|
Pal4[i].rgbRed = Pal3[i].rgbtBlue;
|
|
Pal4[i].rgbReserved = 0;
|
|
}
|
|
memcpy(lpBMP, Pal4, sizeof(Pal4));
|
|
|
|
if (g_bUseTrans)
|
|
// convert the transparent color index to COLORREF
|
|
crTrans = RGB(Pal4[crTrans].rgbRed,Pal4[crTrans].rgbGreen,
|
|
Pal4[crTrans].rgbBlue);
|
|
|
|
LPBYTE lpTemp = lpBMP + sizeof(Pal4);
|
|
ReadGIFInterlacedImage (lpTemp, iflHandle, bi.biHeight, dwWidthInBytes);
|
|
|
|
}
|
|
break;
|
|
/* case 1010101:
|
|
{
|
|
|
|
int IM[] = { 8, 8, 4, 2 }; // interlace multiplier
|
|
//int IO[] = { 1, 5, 3 ,2 }; // interface offset
|
|
int IO[] = { 0, 4, 2,1 };
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
lpBMP = lpTemp + bi.biSizeImage - dwWidthInBytes*IO[j];
|
|
for (i = 0; i < abs(bi.biHeight) && lpBMP >= lpTemp;
|
|
lpBMP-=dwWidthInBytes*IM[j], i+=8)
|
|
{
|
|
// read in one line at a time
|
|
iflRead(iflHandle, (LPBYTE)lpBMP, 1);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}*/
|
|
#ifdef PNG_SUPPORT
|
|
case IFLSEQ_ADAM7_INTERLACED:
|
|
{
|
|
|
|
// get color palette info first...
|
|
RGBTRIPLE Pal3[MAX_PAL_SIZE];
|
|
RGBQUAD Pal4[MAX_PAL_SIZE];
|
|
iflErr = iflControl(iflHandle, IFLCMD_PALETTE, 0, 0, &Pal3);
|
|
|
|
for (i = 0; i < MAX_PAL_SIZE; i++)
|
|
{
|
|
Pal4[i].rgbBlue = Pal3[i].rgbtRed;
|
|
Pal4[i].rgbGreen = Pal3[i].rgbtGreen;
|
|
Pal4[i].rgbRed = Pal3[i].rgbtBlue;
|
|
Pal4[i].rgbReserved = 0;
|
|
}
|
|
memcpy(lpBMP, Pal4, sizeof(Pal4));
|
|
|
|
if (g_bUseTrans)
|
|
// convert the transparent color index to COLORREF
|
|
crTrans = RGB(Pal4[crTrans].rgbRed,
|
|
Pal4[crTrans].rgbGreen,
|
|
Pal4[crTrans].rgbBlue);
|
|
/////////////////////////////
|
|
HANDLE hHeap = GetProcessHeap();
|
|
LPBYTE *ppbRGBRowPtrs =(LPBYTE *)AllocateImageSpace(hHeap,
|
|
bi.biHeight, dwWidthInBytes, /*bi.biWidth, */sizeof(BYTE));
|
|
|
|
if (ppbRGBRowPtrs != NULL)
|
|
{
|
|
// First get the image. This function will de-interlace the image
|
|
// AND any alpha channel information: it will also resize the alpha
|
|
// channel data structure to the image height from the number of
|
|
// raster lines, if necessary.
|
|
iflErr = ReadADAM7InterlacedImage(ppbRGBRowPtrs, iflHandle,
|
|
bi.biHeight, bi.biWidth,
|
|
sizeof(BYTE)*3, iflClass);
|
|
/////////////////////////////
|
|
|
|
if (iflErr == IFLERR_NONE)
|
|
{
|
|
lpBMP += bi.biClrUsed*sizeof(RGBQUAD) + bi.biSizeImage -
|
|
dwWidthInBytes;
|
|
for (i = 0;i < abs(bi.biHeight);lpBMP-=dwWidthInBytes, i++)
|
|
{
|
|
// read in one line at a time
|
|
memcpy((LPBYTE)lpBMP, ppbRGBRowPtrs[i], dwWidthInBytes);
|
|
|
|
// need to swap RED with BLUE for internal DIB display
|
|
for (j = 0; j < bi.biWidth*3; j+=3)
|
|
{
|
|
byTemp = *(lpBMP+j);
|
|
*(lpBMP+j) = *(lpBMP+j+2);
|
|
*(lpBMP+j+2) = byTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
ppbRGBRowPtrs = (LPBYTE *)FreeImageSpace(hHeap,
|
|
ppbRGBRowPtrs,
|
|
bi.biHeight);
|
|
}
|
|
break;
|
|
|
|
}
|
|
#endif // PNG_SUPPORT
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
exit:
|
|
iflClose(iflHandle);
|
|
iflFreeHandle(iflHandle);
|
|
|
|
return (HGLOBAL)lpStart;
|
|
|
|
#endif // _USE_IFL_API
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _USE_FLT_API
|
|
|
|
HINSTANCE hLib = NULL;
|
|
FILESPEC fileSpec; // file to load
|
|
GRPI pict;
|
|
UINT rc; // return code
|
|
HANDLE hPrefMem = NULL; // filter-supplied preferences
|
|
UINT wFilterType; // 2 = graphics filter
|
|
char szHandler[128];
|
|
HGLOBAL hDib = NULL;
|
|
|
|
PFNGetFilterInfo lpfnGetFilterInfo;
|
|
PFNImportGr lpfnImportGr;
|
|
|
|
if (!GetHandlerForFile(TRUE, szFileName, szHandler, sizeof(szHandler)))
|
|
return FALSE;
|
|
|
|
if (szHandler[0] == 0)
|
|
return FALSE;
|
|
|
|
if ((hLib = LoadLibrary(szHandler)) == NULL)
|
|
goto exit;
|
|
|
|
// get a pointer to the ImportGR function
|
|
lpfnGetFilterInfo = (PFNGetFilterInfo)GetProcAddress(hLib, "GetFilterInfo");
|
|
lpfnImportGr = (PFNImportGr)GetProcAddress(hLib, "ImportGr");
|
|
|
|
if (lpfnGetFilterInfo == NULL)
|
|
lpfnGetFilterInfo = (PFNGetFilterInfo)GetProcAddress(hLib, "GetFilterInfo@16");
|
|
|
|
if (lpfnImportGr == NULL)
|
|
lpfnImportGr = (PFNImportGr)GetProcAddress(hLib, "ImportGr@16");
|
|
|
|
if (lpfnImportGr == NULL)
|
|
goto exit;
|
|
|
|
if (lpfnGetFilterInfo != NULL)
|
|
{
|
|
wFilterType = (*lpfnGetFilterInfo)
|
|
((short) 2, // interface version no.
|
|
(char *)NULL, // unused
|
|
(HANDLE *) &hPrefMem, // fill in: preferences
|
|
(DWORD) 0x00020000); // unused in Windows
|
|
|
|
// the return value is the type of filter: 0=error,
|
|
// 1=text-filter, 2=graphics-filter
|
|
if (wFilterType != 2)
|
|
goto exit;
|
|
}
|
|
|
|
fileSpec.slippery = FALSE; // TRUE if file may disappear
|
|
fileSpec.write = FALSE; // TRUE if open for write
|
|
fileSpec.unnamed = FALSE; // TRUE if unnamed
|
|
fileSpec.linked = FALSE; // Linked to an FS FCB
|
|
fileSpec.mark = FALSE; // Generic mark bit
|
|
fileSpec.dcbFile = 0L;
|
|
//the converters need a pathname without spaces...
|
|
|
|
GetShortPathName(szFileName, fileSpec.szName, sizeof(fileSpec.szName));
|
|
|
|
pict.hmf = NULL;
|
|
|
|
rc = (*lpfnImportGr)
|
|
(NULL, // "the target DC" (printer?)
|
|
(FILESPEC *) &fileSpec, // file to read
|
|
(GRPI *) &pict, // fill in: result metafile
|
|
(HANDLE) hPrefMem); // preferences memory
|
|
|
|
if (pict.hmf != NULL)
|
|
{
|
|
if (rc == 0)
|
|
{
|
|
// find the BITMAPINFO in the returned metafile
|
|
|
|
LPMETAHEADER lpMetaHeader = (LPMETAHEADER) GlobalLock(pict.hmf);
|
|
|
|
LPBITMAPINFOHEADER lpbi = FindBitmapInfo(lpMetaHeader);
|
|
|
|
if (lpbi != NULL)
|
|
{
|
|
// copy the DIB
|
|
|
|
SIZE_T nSize = FindDibSize(lpbi);
|
|
|
|
hDib = GlobalAlloc(GMEM_FIXED, nSize);
|
|
|
|
CopyMemory(hDib, lpbi, nSize);
|
|
}
|
|
|
|
GlobalUnlock(pict.hmf);
|
|
}
|
|
|
|
GlobalFree(pict.hmf);
|
|
}
|
|
|
|
exit:
|
|
if (hPrefMem != NULL)
|
|
GlobalFree(hPrefMem);
|
|
|
|
if (hLib)
|
|
FreeLibrary(hLib);
|
|
|
|
return hDib;
|
|
|
|
#endif // _USE_FLT_API
|
|
return NULL;
|
|
}
|
|
|
|
CGdiplusInit::CGdiplusInit(
|
|
Gdiplus::DebugEventProc debugEventCallback /*= 0*/,
|
|
BOOL suppressBackgroundThread /*= FALSE*/,
|
|
BOOL suppressExternalCodecs /*= FALSE*/
|
|
)
|
|
{
|
|
Gdiplus::GdiplusStartupInput StartupInput(
|
|
debugEventCallback,
|
|
suppressBackgroundThread,
|
|
suppressExternalCodecs
|
|
);
|
|
|
|
StartupStatus = GdiplusSafeStartup(&Token, &StartupInput, this);
|
|
}
|
|
|
|
CGdiplusInit::~CGdiplusInit()
|
|
{
|
|
if (StartupStatus == Gdiplus::Ok)
|
|
{
|
|
Gdiplus::GdiplusShutdown(Token);
|
|
}
|
|
}
|
|
|
|
Gdiplus::Status
|
|
CGdiplusInit::GdiplusSafeStartup(
|
|
ULONG_PTR *token,
|
|
const Gdiplus::GdiplusStartupInput *input,
|
|
Gdiplus::GdiplusStartupOutput *output
|
|
)
|
|
{
|
|
__try
|
|
{
|
|
return Gdiplus::GdiplusStartup(token, input, output);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return Gdiplus::GdiplusNotInitialized;
|
|
}
|
|
}
|
|
|
|
BOOL GetGdiplusDecoders(UINT *pnCodecs, Gdiplus::ImageCodecInfo **ppCodecs)
|
|
{
|
|
ASSERT(pnCodecs);
|
|
ASSERT(ppCodecs);
|
|
|
|
*ppCodecs = 0;
|
|
*pnCodecs = 0;
|
|
|
|
if (theApp.GdiplusInit.StartupStatus == Gdiplus::Ok)
|
|
{
|
|
__try
|
|
{
|
|
UINT cbCodecs;
|
|
|
|
if (Gdiplus::GetImageDecodersSize(pnCodecs, &cbCodecs) == Gdiplus::Ok)
|
|
{
|
|
if (*pnCodecs > 0)
|
|
{
|
|
*ppCodecs = (Gdiplus::ImageCodecInfo *) LocalAlloc(LMEM_FIXED, cbCodecs);
|
|
|
|
if (*ppCodecs != 0)
|
|
{
|
|
if (Gdiplus::GetImageDecoders(*pnCodecs, cbCodecs, *ppCodecs) == Gdiplus::Ok)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
LocalFree(*ppCodecs);
|
|
|
|
*ppCodecs = 0;
|
|
*pnCodecs = 0;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetGdiplusEncoders(UINT *pnCodecs, Gdiplus::ImageCodecInfo **ppCodecs)
|
|
{
|
|
ASSERT(pnCodecs);
|
|
ASSERT(ppCodecs);
|
|
|
|
*ppCodecs = 0;
|
|
*pnCodecs = 0;
|
|
|
|
if (theApp.GdiplusInit.StartupStatus == Gdiplus::Ok)
|
|
{
|
|
__try
|
|
{
|
|
UINT cbCodecs;
|
|
|
|
if (Gdiplus::GetImageEncodersSize(pnCodecs, &cbCodecs) == Gdiplus::Ok)
|
|
{
|
|
if (*pnCodecs > 0)
|
|
{
|
|
*ppCodecs = (Gdiplus::ImageCodecInfo *) LocalAlloc(LMEM_FIXED, cbCodecs);
|
|
|
|
if (*ppCodecs != 0)
|
|
{
|
|
if (Gdiplus::GetImageEncoders(*pnCodecs, cbCodecs, *ppCodecs) == Gdiplus::Ok)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
LocalFree(*ppCodecs);
|
|
|
|
*ppCodecs = 0;
|
|
*pnCodecs = 0;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetClsidOfEncoder(REFGUID guidFormatID, CLSID *pClsid)
|
|
{
|
|
Gdiplus::ImageCodecInfo *pCodecs = 0;
|
|
UINT nCodecs = 0;
|
|
|
|
GetGdiplusEncoders(&nCodecs, &pCodecs);
|
|
|
|
for (UINT i = 0; i < nCodecs; ++i)
|
|
{
|
|
if (pCodecs[i].FormatID == guidFormatID)
|
|
{
|
|
if (pClsid)
|
|
{
|
|
*pClsid = pCodecs[i].Clsid;
|
|
}
|
|
|
|
LocalFree(pCodecs);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
LocalFree(pCodecs);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HGLOBAL LoadDIBGdiplus(LPCTSTR szFileName, GUID *pguidFltTypeUsed)
|
|
{
|
|
// check that the BMP encoder exists
|
|
|
|
CLSID ClsidBmpEncoder;
|
|
|
|
if (GetClsidOfEncoder(WiaImgFmt_BMP, &ClsidBmpEncoder))
|
|
{
|
|
// let GDI+ import the file
|
|
|
|
USES_CONVERSION;
|
|
|
|
Gdiplus::Bitmap image(T2CW(szFileName));
|
|
|
|
if (image.GetLastStatus() == Gdiplus::Ok)
|
|
{
|
|
// read the image type
|
|
|
|
ASSERT(pguidFltTypeUsed);
|
|
|
|
image.GetRawFormat(pguidFltTypeUsed);
|
|
|
|
// create a stream that emulates a bmp file
|
|
|
|
CComPtr<CBmpStream> pStream;
|
|
|
|
if (CBmpStream::Create(&pStream) == S_OK)
|
|
{
|
|
// convert the image into a BMP
|
|
|
|
if (image.Save(pStream, &ClsidBmpEncoder, 0) == Gdiplus::Ok)
|
|
{
|
|
return pStream->GetBuffer();
|
|
}
|
|
|
|
pStream->FreeBuffer();
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HGLOBAL LoadDIBFromFile(LPCTSTR szFileName, GUID *pguidFltTypeUsed)
|
|
{
|
|
// Try GDI+ filters first. If it fails to convert the image or
|
|
// if it's not available, try the old method
|
|
|
|
HGLOBAL hResult = 0;
|
|
|
|
if (theApp.GdiplusInit.StartupStatus == Gdiplus::Ok)
|
|
{
|
|
__try
|
|
{
|
|
hResult = LoadDIBGdiplus(szFileName, pguidFltTypeUsed);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
|
|
if (!hResult)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
hResult = LoadDIBFromFileA(T2CA(szFileName), pguidFltTypeUsed);
|
|
}
|
|
|
|
return hResult;
|
|
}
|