/* LOADIMAG.C Frosting: Master Theme Selector for Windows '95 Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved. */ #include #include #include #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 #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 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