|
|
/* LOADIMAG.C
Frosting: Master Theme Selector for Windows '95 Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved. */
#include <windows.h>
#include <windowsx.h>
#include <mbctype.h>
#include "stdlib.h"
#include "loadimag.h"
#include "halftone.h"
#include "dither.h"
#include "htmlprev.h"
#include "schedule.h" // IsPlatformNT() function
//DEBUG
//#include "stdio.h"
//TCHAR szDebug[512];
#ifdef DBG
#define _DEBUG
#endif
#ifdef DEBUG
#define _DEBUG
#endif
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#define SZSIZEINBYTES(x) (lstrlen(x)*sizeof(TCHAR)+1)
#ifdef _DEBUG
#include <mmsystem.h>
#define TIMESTART(sz) { TCHAR szTime[80]; DWORD time = timeGetTime();
#define TIMESTOP(sz) time = timeGetTime() - time; wsprintf(szTime, TEXT("%s took %d.%03d sec\r\n"), sz, time/1000, time%1000); OutputDebugString(szTime); }
#else
#define TIMESTART(sz)
#define TIMESTOP(sz)
#endif
// regutils.c
extern VOID ExpandSZ(LPTSTR);
static BOOL bVersion2; //peihwal : add for JPEG32.FLT interface
//
// structures for dealing with import filters.
//
#pragma pack(2) /* Switch on 2-byte packing. */
typedef struct { unsigned short slippery: 1; /* True if file may disappear. */ unsigned short write : 1; /* True if open for write. */ unsigned short unnamed: 1; /* True if unnamed. */ unsigned short linked : 1; /* Linked to an FS FCB. */ unsigned short mark : 1; /* Generic mark bit. */ union { char ext[4]; /* File extension. */ HFILE hfEmbed; /* handle to file containing */ /* graphic (for import) */ }; unsigned short handle; /* not used */ char fullName[260]; /* Full path name and file name. */ DWORD filePos; /* Position in file of... */ } FILESPEC; #pragma pack()
typedef struct { HANDLE h; RECT bbox; int inch; } GRPI;
// 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) { LPCTSTR pszDot;
for (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_szHandlerKey[] = TEXT("SOFTWARE\\Microsoft\\Shared Tools\\Graphics Filters\\Import"); static const TCHAR c_szName[] = TEXT("Name"); static const TCHAR c_szPath[] = TEXT("Path"); static const TCHAR c_szExts[] = TEXT("Extensions"); #pragma data_seg()
BOOL GetFilterInfo(int i, LPTSTR szName, UINT cbName, LPTSTR szExt, UINT cbExt, LPTSTR szHandler, UINT cbHandler) { HKEY hkey; HKEY hkeyT; DWORD dwType = 0; TCHAR ach[80]; BOOL f=FALSE;
if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szHandlerKey, &hkey) == 0) { if (RegEnumKey(hkey, i, ach, ARRAYSIZE(ach))==0) { if (RegOpenKey(hkey, ach, &hkeyT) == 0) { if (szName) { szName[0]=0; RegQueryValueEx(hkeyT, c_szName, NULL, NULL, (LPBYTE)szName, &cbName); } if (szExt) { szExt[0]=0; RegQueryValueEx(hkeyT, c_szExts, NULL, NULL, (LPBYTE)szExt, &cbExt); } if (szHandler) { szHandler[0]=0; RegQueryValueEx(hkeyT, c_szPath, NULL, &dwType, (LPBYTE)szHandler, &cbHandler); if (REG_EXPAND_SZ == dwType) ExpandSZ(szHandler); }
RegCloseKey(hkeyT); f = TRUE; } } RegCloseKey(hkey); } return f; }
//
// GetHandlerForFile
//
// find a import filter for the given file.
//
// if the file does not need a handler return ""
//
BOOL GetHandlerForFile(LPCTSTR szFile, LPTSTR szHandler, UINT cb) { LPCTSTR ext; TCHAR ach[40]; int i; BOOL f = FALSE;
*szHandler = 0;
if (szFile == NULL) return FALSE;
// find the extension
ext = FindExtension(szFile);
for (i=0; GetFilterInfo(i, NULL, 0, ach, sizeof(ach), szHandler, cb); i++) { if (lstrcmpi(ext+1, ach) == 0) break; else *szHandler = 0; }
// if the handler file does not exist fail.
if (*szHandler && GetFileAttributes(szHandler) != -1) f = TRUE;
//if we cant find a handler hard code JPEG
if (!f && lstrcmpi(ext,TEXT(".jpg")) == 0) { lstrcpy(szHandler, TEXT("JPEGIM32.FLT")); // lstrcpy(szHandler, TEXT("JPEG32.FLT"));
f = TRUE; }
//if we cant find a handler hard code PCX
if (!f && lstrcmpi(ext, TEXT(".pcx")) == 0) { lstrcpy(szHandler, TEXT("PCXIMP32.FLT")); f = TRUE; }
return f; }
//
// FindBitmapInfo
//
// find the DIB bitmap in a memory meta file...
//
LPBITMAPINFOHEADER FindBitmapInfo(LPMETAHEADER pmh) { LPMETARECORD pmr;
for (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; } // add for new filter JPEG32.FLT
static LPVOID lpWMFBits = NULL; //
// FindBitmapInfoFromWMF
//
// retrieve metafile header
//
LPBITMAPINFOHEADER FindBitmapInfoFromWMF(GRPI* pict) { UINT uiSizeBuf = 0; LPBITMAPINFOHEADER lpbi = NULL;
//get the size of the metafile associated with hMF...
if ((uiSizeBuf = GetMetaFileBitsEx(pict->h, 0, NULL))) { //allocate buffer
lpWMFBits = GlobalAllocPtr(GHND, uiSizeBuf);
//get the bits of the Windows metafile associated with hMF...
if (!lpWMFBits) { return NULL; }
//make a local copy of it in our segment
if ( GetMetaFileBitsEx(pict->h, uiSizeBuf, lpWMFBits)) { lpbi = FindBitmapInfo((LPMETAHEADER)lpWMFBits); } } return (lpbi); } // end for new filter JPEG32.FLT
//
// LoadDIBFromFile
//
// load a image file using a image import filter.
//
HRESULT LoadDIBFromFile(IN LPCTSTR szFileName, IN BITMAP_AND_METAFILE_COMBO * pBitmapAndMetaFile) { HRESULT hr = S_OK; HMODULE hModule; FILESPEC fileSpec; // file to load
GRPI pict; UINT rc; // return code
HANDLE hPrefMem = NULL; // filter-supplied preferences
UINT wFilterType; // 2 = graphics filter
TCHAR szHandler[MAX_PATH]; // changed from 128 to MAX_PATH
LPVOID lpMeta = NULL; #ifdef UNICODE
TCHAR szFileNameW[MAX_PATH]; #endif
UINT (FAR PASCAL *GetFilterInfo)(short v, LPSTR szFilterExten, HANDLE FAR * fph1, HANDLE FAR * fph2); UINT (FAR PASCAL *ImportGR)(HDC hdc, FILESPEC FAR *lpfs, GRPI FAR *p, HANDLE hPref);
pBitmapAndMetaFile->pBitmapInfoHeader = NULL; pBitmapAndMetaFile->hMetaFile = NULL;
if (!GetHandlerForFile(szFileName, szHandler, sizeof(szHandler))) return hr;
if (szHandler[0] == 0) return hr;
TIMESTART(TEXT("LoadDIBFromFile"));
hModule = LoadLibrary(szHandler);
if (hModule == NULL) goto exit;
/* get a pointer to the ImportGR function */ (FARPROC)GetFilterInfo = GetProcAddress(hModule, "GetFilterInfo"); (FARPROC)ImportGR = GetProcAddress(hModule, "ImportGr");
if (GetFilterInfo == NULL) (FARPROC)GetFilterInfo = GetProcAddress(hModule, "GetFilterInfo@16");
if (ImportGR == NULL) (FARPROC)ImportGR = GetProcAddress(hModule, "ImportGr@16");
if (ImportGR == NULL) goto exit;
if (GetFilterInfo != NULL) { wFilterType = (*GetFilterInfo) ((short) 2, // interface version no.
(LPSTR)"", // end of .INI entry
(HANDLE FAR *) &hPrefMem, // fill in: preferences
(HANDLE FAR *) NULL); // 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.fType = 0L; // The file type
fileSpec.handle = 0; // MS-DOS open file handle
fileSpec.filePos = 0L;
//the converters need a pathname without spaces!
#ifdef UNICODE
GetShortPathName(szFileName, szFileNameW, ARRAYSIZE(szFileNameW)); wcstombs(fileSpec.fullName, szFileNameW, ARRAYSIZE(fileSpec.fullName)); #else
GetShortPathName(szFileName, fileSpec.fullName, ARRAYSIZE(fileSpec.fullName)); #endif
pict.h = NULL;
rc = (*ImportGR) (NULL, // "the target DC" (printer?)
(FILESPEC FAR *) &fileSpec, // file to read
(GRPI FAR *) &pict, // fill in: result metafile
(HANDLE) hPrefMem); // preferences memory
if (rc != 0 || pict.h == NULL) goto exit;
//
// find the BITMAPINFO in the returned metafile
// this saves us from creating a metafile and duplicating
// all the memory.
//
// add for new filter JPEG32.FLT
lpMeta = GlobalLock(pict.h); rc = GetLastError();
bVersion2 = (lpMeta) ? TRUE : FALSE;
//
// The whole "bversion2" logic above seems fundamentally flawed.
// It is broken under NT, that's for certain. Since I have had
// limited luck getting info on the graphics filter interface
// and the "bversion2" logic, I am going to assume that for the
// NT world we don't have a version2 filter.
//
if (IsPlatformNT()) bVersion2 = FALSE;
if ( bVersion2 ) { pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfo((LPMETAHEADER)lpMeta); } else { pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfoFromWMF(&pict); pBitmapAndMetaFile->pBitmapInfoHeader->biYPelsPerMeter = 0x12345678; } // pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfo((LPMETAHEADER)GlobalLock(pict.h));
// add for new filter JPEG32.FLT
if (pBitmapAndMetaFile->pBitmapInfoHeader == NULL) // cant find it bail
{ GlobalFree(pict.h); } else { // BUGBUG This will not work in Win64 - throwing away high 32 bits
pBitmapAndMetaFile->hMetaFile = pict.h; }
exit: if (hPrefMem != NULL) GlobalFree(hPrefMem);
if (hModule) FreeLibrary(hModule);
TIMESTOP(TEXT("LoadDIBFromFile"));
return hr; }
//
// FreeDIB
//
void FreeDIB(BITMAP_AND_METAFILE_COMBO bam) { if (bam.pBitmapInfoHeader) { if (bam.hMetaFile && (bam.pBitmapInfoHeader->biYPelsPerMeter == 0x12345678)) { // add for new filter JPEG32.FLT
// GlobalFree((HANDLE)lpbi->biXPelsPerMeter);
//done with the actual memory used to store bits so nuke it...
if ( !bVersion2 ) { if ( lpWMFBits ) { // DSCHOTT 98JUL20
// Moved this DeleteMetaFile() from after this
// IF clause up to here since lpbi->biXPelsPerMeter
// is not valid after this GlobalFreePtr() call.
DeleteMetaFile(bam.hMetaFile);
GlobalFreePtr(lpWMFBits); lpWMFBits = NULL; }
// DSCHOTT moved up inside IF clause before GlobalFreePtr().
// DeleteMetaFile((HMETAFILE)lpbi->biXPelsPerMeter);
} else // bVersion2
{ GlobalFree(bam.hMetaFile); } // add for new filter JPEG32.FLT
} else { GlobalFree(GlobalHandle(bam.pBitmapInfoHeader)); }
} // end if lpbi
} // FreeDIB()
#define DIVIDE_SAFE(nNumber) ((0 == (nNumber)) ? 1 : (nNumber))
//
// LoadImageFromFile
//
// load a image file using a image import filter.
//
HBITMAP LoadImageFromFile(LPCTSTR szFileName, BITMAP_AND_METAFILE_COMBO * pBitmapMetaFile, int width, int height, int bpp, int dither) { HBITMAP hbm=NULL; HBITMAP hbmT; HBITMAP hbmFree=NULL; HDC hdc=NULL; BITMAP_AND_METAFILE_COMBO bamFree = {0}; HCURSOR hcur; LPBYTE pbSrc; LPBYTE pbDst; LPCTSTR ext; TCHAR ach[MAX_PATH]; //dschott changed from 128 to MAX_PATH
int displaybpp; UINT rastercaps; DIBSECTION ds; struct { BITMAPINFOHEADER bi; DWORD ct[256]; } dib;
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT)); // TIMESTART(TEXT("LoadImageFromFile"));
if (pBitmapMetaFile && (pBitmapMetaFile->pBitmapInfoHeader == NULL)) { // find the extension
ext = FindExtension(szFileName);
// if it is a bitmap file no handler is needed, we can just call LoadImage
if (lstrcmpi(ext,TEXT(".bmp")) == 0 || lstrcmpi(ext,TEXT(".dib")) == 0 || lstrcmpi(ext,TEXT(".rle")) == 0 || ext[0] != TEXT('.')) { if (width < 0 && height < 0) { DWORD dw = GetImageTitle(szFileName, ach, sizeof(ach)); width = (int)LOWORD(dw) * -width / DIVIDE_SAFE(GetSystemMetrics(SM_CXSCREEN)); height = (int)HIWORD(dw) * -height / DIVIDE_SAFE(GetSystemMetrics(SM_CYSCREEN)); } hbm = LoadImage(NULL, szFileName, IMAGE_BITMAP, width, height, LR_LOADFROMFILE|LR_CREATEDIBSECTION); goto exit; }
TIMESTART(TEXT("LoadDIBFromFile")); LoadDIBFromFile(szFileName, pBitmapMetaFile); bamFree.pBitmapInfoHeader = pBitmapMetaFile->pBitmapInfoHeader; bamFree.hMetaFile = pBitmapMetaFile->hMetaFile; TIMESTOP(TEXT("LoadDIBFromFile")); }
if (pBitmapMetaFile == NULL) // cant find it bail
goto exit;
//
// figure out the lpBits pointer we need to pass to StretchDIBits
//
pbSrc = (LPBYTE)pBitmapMetaFile->pBitmapInfoHeader + pBitmapMetaFile->pBitmapInfoHeader->biSize + pBitmapMetaFile->pBitmapInfoHeader->biClrUsed * sizeof(RGBQUAD);
if (pBitmapMetaFile->pBitmapInfoHeader->biClrUsed == 0 && pBitmapMetaFile->pBitmapInfoHeader->biBitCount <= 8) pbSrc = (LPBYTE)((LPDWORD)pbSrc + (1 << pBitmapMetaFile->pBitmapInfoHeader->biBitCount));
hdc = CreateCompatibleDC(NULL);
if (hdc == NULL) goto exit;
displaybpp = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL); rastercaps = GetDeviceCaps(hdc, RASTERCAPS);
//
// create a DIBSection and draw the DIB into it.
// we need to figure out what type of DIBSection to
// make. the caller can ask for a specific bit depth (bpp>0)
// or the same bit depth as the image (bpp==0) or the bit depth
// of the display (bpp==-1) the same goes for width/height
//
hmemcpy(&dib, pBitmapMetaFile->pBitmapInfoHeader, sizeof(dib)); dib.bi.biClrUsed = 0; dib.bi.biXPelsPerMeter = 0; dib.bi.biYPelsPerMeter = 0;
if (width < 0) width = dib.bi.biWidth * -width / DIVIDE_SAFE(GetSystemMetrics(SM_CXSCREEN));
if (height < 0) height = dib.bi.biHeight * -height / DIVIDE_SAFE(GetSystemMetrics(SM_CYSCREEN));
if (width > 0) dib.bi.biWidth = width;
if (height > 0) dib.bi.biHeight = height;
// get the best bit depth to use on this display.
if (bpp == -1 && dib.bi.biBitCount > 8) { if (displaybpp > 8) bpp = 16; else bpp = 8; }
// we may need to figure out a palette for this image
//
// if we can find a file with the same name and a extension of .PAL
// use that as the palette, else use a default set of colors.
//
if (bpp == 8) { dib.bi.biBitCount = 8; dib.bi.biCompression = 0; if (pBitmapMetaFile->pBitmapInfoHeader->biBitCount > 8) { HDC screen; lstrcpy(ach, szFileName); lstrcpy((LPTSTR)FindExtension(ach),TEXT(".pal"));
// LoadPaletteFromFile("") will give us back the HT colors...
if (dither == DITHER_STANDARD || dither == DITHER_STANDARD_HYBRID) { ach[0] = 0; }
screen = GetDC(NULL); dib.bi.biClrUsed = LoadPaletteFromFile(ach, dib.ct, (rastercaps & RC_PALETTE) ? NULL : screen); ReleaseDC(NULL, screen); } } #if 0
else if (bpp == 565) { dib.bi.biBitCount = 16; dib.bi.biCompression = BI_BITFIELDS; dib.ct[0] = 0x0000F800; dib.ct[1] = 0x000007E0; dib.ct[2] = 0x0000001F; } else if (bpp == 555) { dib.bi.biBitCount = 16; dib.bi.biCompression = 0; } #endif
else if (bpp > 0) { dib.bi.biBitCount = (WORD)bpp; dib.bi.biCompression = 0; }
//
// check to see if we are dithering, and if we are also stretching
// we need to do the stretching NOW so we dont end up stretching
// dither patterns, we also do this before calling CreateDIBSection
// to make the memory usage of this already piggy code smaller
//
if (dither && pBitmapMetaFile->pBitmapInfoHeader->biBitCount == 24 && (bpp == 16 || bpp == 8)) { if (dib.bi.biWidth!=pBitmapMetaFile->pBitmapInfoHeader->biWidth || dib.bi.biHeight!=pBitmapMetaFile->pBitmapInfoHeader->biHeight) { // TIMESTART(TEXT("Stretch"));
if (hbmFree = LoadImageFromFile(NULL, pBitmapMetaFile, dib.bi.biWidth, dib.bi.biHeight, 0, 0)) { GetObject(hbmFree, sizeof(ds), &ds); pbSrc = ds.dsBm.bmBits; pBitmapMetaFile->pBitmapInfoHeader = &ds.dsBmih; if (bamFree.pBitmapInfoHeader != NULL) { FreeDIB(bamFree); bamFree.pBitmapInfoHeader = NULL; bamFree.hMetaFile = NULL; } } // TIMESTOP(TEXT("Stretch"));
} } else { dither = 0; }
// make the DIBSection what the caller wants.
hbm = CreateDIBSection(hdc, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS, &pbDst, NULL, 0);
if (hbm == NULL) goto exit;
hbmT = SelectObject(hdc, hbm); SetStretchBltMode(hdc, COLORONCOLOR);
if (dither) { TIMESTART(TEXT("Dithering"));
if ((dither == DITHER_HALFTONE) && (dib.bi.biBitCount == 8)) { HalftoneImage(hdc, hbm, pBitmapMetaFile->pBitmapInfoHeader, pbSrc); } else { DitherImage(hdc, hbm, pBitmapMetaFile->pBitmapInfoHeader, pbSrc, ((dib.bi.biBitCount == 16) || ((dither != DITHER_STANDARD) && (dither != DITHER_CUSTOM)))); }
TIMESTOP(TEXT("Dithering")); } else { //
// now draw the DIB into the DIBSection, GDI will handle all
// the format conversion here.
//
TIMESTART(TEXT("StretchDIBits")); StretchDIBits(hdc, 0, 0, dib.bi.biWidth, dib.bi.biHeight, 0, 0, pBitmapMetaFile->pBitmapInfoHeader->biWidth, pBitmapMetaFile->pBitmapInfoHeader->biHeight, pbSrc, (LPBITMAPINFO)pBitmapMetaFile->pBitmapInfoHeader, DIB_RGB_COLORS, SRCCOPY); TIMESTOP(TEXT("StretchDIBits")); } SelectObject(hdc, hbmT);
exit: if (hdc) DeleteDC(hdc);
if (bamFree.pBitmapInfoHeader != NULL) FreeDIB(bamFree);
if (hbmFree) DeleteObject(hbmFree);
if (hcur) SetCursor(hcur);
// TIMESTOP(TEXT("LoadImageFromFile"));
return hbm; }
//
// LoadPaletteFromFile
//
DWORD LoadPaletteFromFile(LPCTSTR szFile, LPDWORD rgb, HDC hdcNearest) { HANDLE fh; DWORD dwBytesRead; UINT i; struct { DWORD dwRiff; DWORD dwFileSize; DWORD dwPal; DWORD dwData; DWORD dwDataSize; WORD palVersion; WORD palNumEntries; DWORD rgb[256]; } pal;
pal.dwRiff = 0;
// read in the palette file.
fh = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh != INVALID_HANDLE_VALUE) { if (!ReadFile(fh, (LPVOID)&pal, sizeof(pal), &dwBytesRead, NULL)) { NULL; // We failed. We check later but this line appeases PREFIX.
}
CloseHandle(fh); }
// if the file is not a palette file, or does not exist
// default to the halftone colors.
if (pal.dwRiff != 0x46464952 || // 'RIFF'
pal.dwPal != 0x204C4150 || // 'PAL '
pal.dwData != 0x61746164 || // 'data'
pal.palVersion != 0x0300 || pal.palNumEntries > 256 || pal.palNumEntries < 1) { HPALETTE hpal = CreateHalftonePalette(NULL);
if (hpal) { GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY)pal.rgb); DeleteObject(hpal); }
pal.palNumEntries = 256; }
for (i = 0; i < pal.palNumEntries; i++) { COLORREF c = pal.rgb[i];
if (hdcNearest) c = GetNearestColor(hdcNearest, c);
rgb[i] = RGB(GetBValue(c),GetGValue(c), GetRValue(c)); }
return pal.palNumEntries; }
//
// magic number we write to the file so we can make sure the
// title string is realy there.
//
#define TITLE_MAGIC 0x47414D53
//
// SaveImageToFile
//
BOOL SaveImageToFile(HBITMAP hbm, LPCTSTR szFile, LPCTSTR szTitle) { BITMAPFILEHEADER hdr; HANDLE fh; DWORD dwBytesWritten; DWORD dw; HDC hdc; DIBSECTION dib; DWORD ct[256]; #ifdef UNICODE
CHAR szTitleA[MAX_PATH]; UINT uCodePage; #endif
if (GetObject(hbm, sizeof(dib), &dib) == 0) return FALSE;
if (dib.dsBm.bmBits == NULL) return FALSE;
hdc = CreateCompatibleDC(NULL); SelectObject(hdc, hbm); if (dib.dsBmih.biBitCount <= 8) { dib.dsBmih.biClrUsed = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)ct); } else if (dib.dsBmih.biCompression == BI_BITFIELDS) { dib.dsBmih.biClrUsed = 3; ct[0] = dib.dsBitfields[0]; ct[1] = dib.dsBitfields[1]; ct[2] = dib.dsBitfields[2]; } DeleteDC(hdc);
fh = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE) return FALSE;
dw = sizeof(BITMAPFILEHEADER) + dib.dsBmih.biSize + dib.dsBmih.biClrUsed * sizeof(RGBQUAD) + dib.dsBmih.biSizeImage;
hdr.bfType = 0x4d42; // BFT_BITMAP
hdr.bfSize = dw; hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = dw - dib.dsBmih.biSizeImage;
#define WRITE(fh, p, cb) if (!WriteFile(fh, (LPVOID)(p), cb, &dwBytesWritten, NULL)) goto error;
WRITE(fh,&hdr,sizeof(BITMAPFILEHEADER)); WRITE(fh,&dib.dsBmih,dib.dsBmih.biSize); WRITE(fh,&ct,dib.dsBmih.biClrUsed * sizeof(RGBQUAD)); WRITE(fh,dib.dsBm.bmBits, dib.dsBmih.biSizeImage);
if (szTitle && *szTitle) { dw = TITLE_MAGIC; WRITE(fh,&dw, sizeof(dw));
#ifdef UNICODE
// Need to convert the title string to ANSI before writing it
// to the file
uCodePage = _getmbcp(); WideCharToMultiByte(uCodePage, 0, szTitle, -1, szTitleA, MAX_PATH, NULL, NULL);
dw = lstrlenA(szTitleA)+1; WRITE(fh,&dw, sizeof(dw)); WRITE(fh,szTitleA,dw); #else
// No Unicode so no need to convert to ANSI
dw = SZSIZEINBYTES(szTitle)+1; WRITE(fh,&dw, sizeof(dw)); WRITE(fh,szTitle,dw); #endif
}
CloseHandle(fh); return TRUE;
error: CloseHandle(fh); DeleteFile(szFile); return FALSE; }
DWORD GetImageTitle(LPCTSTR szFile, LPTSTR szTitle, UINT cb) { BITMAPFILEHEADER hdr; BITMAPINFOHEADER bi; HANDLE fh; DWORD dwBytesRead; DWORD dw=0; CHAR szTitleA[MAX_PATH]; #ifdef UNICODE
UINT uCodePage; #endif
fh = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE) return FALSE;
dwBytesRead = 0; ReadFile(fh, (LPVOID)&hdr, sizeof(hdr), &dwBytesRead, NULL); if (dwBytesRead != sizeof(hdr)) { goto error; }
if (hdr.bfType != 0x4d42) // BFT_BITMAP
goto error;
if (hdr.bfSize == 0) goto error;
dwBytesRead = 0; if (!ReadFile(fh, (LPVOID)&bi, sizeof(bi), &dwBytesRead, NULL) || (dwBytesRead != sizeof(bi))) { goto error; }
if (bi.biSize != sizeof(bi)) goto error;
SetFilePointer(fh, hdr.bfSize, NULL, FILE_BEGIN); dwBytesRead=0; ReadFile(fh, (LPVOID)&dw, sizeof(dw), &dwBytesRead, NULL);
if (dw != TITLE_MAGIC) goto error;
dwBytesRead=0; ReadFile(fh, (LPVOID)&dw, sizeof(dw), &dwBytesRead, NULL);
if ((dw > cb) || (dwBytesRead != sizeof(dw))) goto error;
dwBytesRead=0; ReadFile(fh, (LPVOID)szTitleA, dw, &dwBytesRead, NULL);
if (dwBytesRead != dw) goto error;
#ifdef UNICODE
// Need to convert the ANSI string to UNICODE.
uCodePage = _getmbcp(); MultiByteToWideChar(uCodePage, 0, szTitleA, -1, szTitle, MAX_PATH); #else
// String should be ANSI, no conversion needed, just copy it to
// the destination buffer.
lstrcpy(szTitle, szTitleA); #endif
CloseHandle(fh); return MAKELONG(bi.biWidth, bi.biHeight);
error: CloseHandle(fh); return MAKELONG(bi.biWidth, bi.biHeight); }
//
// CacheLoadImageFromFile
//
static HBITMAP _hbm; static int _width; static int _height; static int _bpp; static int _dither; static BITMAP_AND_METAFILE_COMBO _dib; static TCHAR _name[MAX_PATH];
HBITMAP CacheLoadImageFromFile(LPCTSTR szFileName, int width, int height, int bpp, int dither) {
TIMESTART(TEXT("CacheLoadImageFromFile"));
if (szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".bmp")) == 0) return LoadImageFromFile(szFileName, NULL, width, height, bpp, dither);
// If it's an HTML file use IThumbnail to create a bmp
if ((szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".htm")) == 0) || (szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".html")) == 0))
{ SetCursor(LoadCursor(NULL, IDC_WAIT)); return HtmlToBmp(szFileName, width, height); }
//
// check our cache.
//
if (szFileName && _hbm != NULL && _width == width && _height == height && _bpp == bpp && _dither == dither && lstrcmpi(szFileName, _name) == 0) { return _hbm; }
if (_hbm) { DeleteObject(_hbm); _hbm = NULL; }
if (_dib.pBitmapInfoHeader == NULL || szFileName == NULL || lstrcmpi(szFileName, _name) != 0) { if (_dib.pBitmapInfoHeader) { FreeDIB(_dib); _dib.pBitmapInfoHeader = NULL; _dib.hMetaFile = NULL; }
if (szFileName == NULL) return NULL;
LoadDIBFromFile(szFileName, &_dib); lstrcpy(_name, szFileName); }
if (_dib.pBitmapInfoHeader == NULL) return NULL;
_hbm = LoadImageFromFile(szFileName, &_dib, width, height, bpp, dither);
if (_hbm) { _width = width; _height = height; _bpp = bpp; _dither = dither; }
TIMESTOP(TEXT("CacheLoadImageFromFile")); return _hbm; }
void CacheDeleteBitmap(HBITMAP hbm) { #if 0
//
// we are already caching the DIB data in memory, so we dont need to cache
// the bitmap
//
DeleteObject(hbm); if (hbm == _hbm) _hbm = NULL; #else
if (hbm != _hbm) DeleteObject(hbm); #endif
}
#ifdef _CONSOLE
#ifndef UNICODE // This console stuff is not UNICODE smart.
#include <stdio.h>
void main (int argc, char **argv) { HBITMAP hbm; int bpp=-1; // default to screen.
char ach[128];
argv++; argc--;
if (argc < 1) { printf("usage: %s [-8 -555 -565 -24 -32] input.jpg output.bmp\n", argv[-1]); exit(-1); }
while (argc > 0 && **argv == '-') { if (lstrcmp(*argv, "-8") == 0) bpp = 8; if (lstrcmp(*argv, "-16") == 0) bpp = 16; if (lstrcmp(*argv, "-555") == 0) bpp = 555; if (lstrcmp(*argv, "-565") == 0) bpp = 565; if (lstrcmp(*argv, "-24") == 0) bpp = 24; if (lstrcmp(*argv, "-32") == 0) bpp = 32; argc--; argv++; }
printf("Loading %s....\n", argv[0]); hbm = LoadImageFromFile(argv[0], 0, 0, bpp);
if (hbm == NULL) { printf("can't load %s\n", argv[0]); exit(-1); }
if (argc > 1) { BITMAP bm; GetObject(hbm, sizeof(bm), &bm);
printf("Writing %d bpp image %s....\n", bm.bmBitsPixel, argv[1]); if (!SaveImageToFile(hbm, argv[1], argv[0])) { printf("can't save %s\n", argv[1]); exit(-1); }
GetImageTitle(argv[1], ach, sizeof(ach)); printf("image title: %s\n", ach); }
exit(0); }
#endif // !UNICODE
#endif // _CONSOLE
|