Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1154 lines
31 KiB

  1. /* LOADIMAG.C
  2. Frosting: Master Theme Selector for Windows '95
  3. Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved.
  4. */
  5. #include <windows.h>
  6. #include <windowsx.h>
  7. #include <mbctype.h>
  8. #include "stdlib.h"
  9. #include "loadimag.h"
  10. #include "halftone.h"
  11. #include "dither.h"
  12. #include "htmlprev.h"
  13. #include "schedule.h" // IsPlatformNT() function
  14. //DEBUG
  15. //#include "stdio.h"
  16. //TCHAR szDebug[512];
  17. #ifdef DBG
  18. #define _DEBUG
  19. #endif
  20. #ifdef DEBUG
  21. #define _DEBUG
  22. #endif
  23. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  24. #define SZSIZEINBYTES(x) (lstrlen(x)*sizeof(TCHAR)+1)
  25. #ifdef _DEBUG
  26. #include <mmsystem.h>
  27. #define TIMESTART(sz) { TCHAR szTime[80]; DWORD time = timeGetTime();
  28. #define TIMESTOP(sz) time = timeGetTime() - time; wsprintf(szTime, TEXT("%s took %d.%03d sec\r\n"), sz, time/1000, time%1000); OutputDebugString(szTime); }
  29. #else
  30. #define TIMESTART(sz)
  31. #define TIMESTOP(sz)
  32. #endif
  33. // regutils.c
  34. extern VOID ExpandSZ(LPTSTR);
  35. static BOOL bVersion2; //peihwal : add for JPEG32.FLT interface
  36. //
  37. // structures for dealing with import filters.
  38. //
  39. #pragma pack(2) /* Switch on 2-byte packing. */
  40. typedef struct {
  41. unsigned short slippery: 1; /* True if file may disappear. */
  42. unsigned short write : 1; /* True if open for write. */
  43. unsigned short unnamed: 1; /* True if unnamed. */
  44. unsigned short linked : 1; /* Linked to an FS FCB. */
  45. unsigned short mark : 1; /* Generic mark bit. */
  46. union {
  47. char ext[4]; /* File extension. */
  48. HFILE hfEmbed; /* handle to file containing */
  49. /* graphic (for import) */
  50. };
  51. unsigned short handle; /* not used */
  52. char fullName[260]; /* Full path name and file name. */
  53. DWORD filePos; /* Position in file of... */
  54. } FILESPEC;
  55. #pragma pack()
  56. typedef struct {
  57. HANDLE h;
  58. RECT bbox;
  59. int inch;
  60. } GRPI;
  61. // returns a pointer to the extension of a file.
  62. //
  63. // in:
  64. // qualified or unqualfied file name
  65. //
  66. // returns:
  67. // pointer to the extension of this file. if there is no extension
  68. // as in "foo" we return a pointer to the NULL at the end
  69. // of the file
  70. //
  71. // foo.txt ==> ".txt"
  72. // foo ==> ""
  73. // foo. ==> "."
  74. //
  75. LPCTSTR FindExtension(LPCTSTR pszPath)
  76. {
  77. LPCTSTR pszDot;
  78. for (pszDot = NULL; *pszPath; pszPath = CharNext(pszPath))
  79. {
  80. switch (*pszPath) {
  81. case TEXT('.'):
  82. pszDot = pszPath; // remember the last dot
  83. break;
  84. case TEXT('\\'):
  85. case TEXT(' '): // extensions can't have spaces
  86. pszDot = NULL; // forget last dot, it was in a directory
  87. break;
  88. }
  89. }
  90. // if we found the extension, return ptr to the dot, else
  91. // ptr to end of the string (NULL extension)
  92. return pszDot ? pszDot : pszPath;
  93. }
  94. //
  95. // GetFilterInfo
  96. //
  97. // 32-bit import filters are listed in the registry...
  98. //
  99. // HKLM\SOFTWARE\Microsoft\Shared Tools\Graphics Filters\Import\XXX
  100. // Path = filename
  101. // Name = friendly name
  102. // Extenstions = file extenstion list
  103. //
  104. #pragma data_seg(".text")
  105. static const TCHAR c_szHandlerKey[] = TEXT("SOFTWARE\\Microsoft\\Shared Tools\\Graphics Filters\\Import");
  106. static const TCHAR c_szName[] = TEXT("Name");
  107. static const TCHAR c_szPath[] = TEXT("Path");
  108. static const TCHAR c_szExts[] = TEXT("Extensions");
  109. #pragma data_seg()
  110. BOOL GetFilterInfo(int i, LPTSTR szName, UINT cbName, LPTSTR szExt, UINT cbExt, LPTSTR szHandler, UINT cbHandler)
  111. {
  112. HKEY hkey;
  113. HKEY hkeyT;
  114. DWORD dwType = 0;
  115. TCHAR ach[80];
  116. BOOL f=FALSE;
  117. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szHandlerKey, &hkey) == 0)
  118. {
  119. if (RegEnumKey(hkey, i, ach, ARRAYSIZE(ach))==0)
  120. {
  121. if (RegOpenKey(hkey, ach, &hkeyT) == 0)
  122. {
  123. if (szName)
  124. {
  125. szName[0]=0;
  126. RegQueryValueEx(hkeyT, c_szName, NULL, NULL, (LPBYTE)szName, &cbName);
  127. }
  128. if (szExt)
  129. {
  130. szExt[0]=0;
  131. RegQueryValueEx(hkeyT, c_szExts, NULL, NULL, (LPBYTE)szExt, &cbExt);
  132. }
  133. if (szHandler)
  134. {
  135. szHandler[0]=0;
  136. RegQueryValueEx(hkeyT, c_szPath, NULL, &dwType, (LPBYTE)szHandler, &cbHandler);
  137. if (REG_EXPAND_SZ == dwType) ExpandSZ(szHandler);
  138. }
  139. RegCloseKey(hkeyT);
  140. f = TRUE;
  141. }
  142. }
  143. RegCloseKey(hkey);
  144. }
  145. return f;
  146. }
  147. //
  148. // GetHandlerForFile
  149. //
  150. // find a import filter for the given file.
  151. //
  152. // if the file does not need a handler return ""
  153. //
  154. BOOL GetHandlerForFile(LPCTSTR szFile, LPTSTR szHandler, UINT cb)
  155. {
  156. LPCTSTR ext;
  157. TCHAR ach[40];
  158. int i;
  159. BOOL f = FALSE;
  160. *szHandler = 0;
  161. if (szFile == NULL)
  162. return FALSE;
  163. // find the extension
  164. ext = FindExtension(szFile);
  165. for (i=0; GetFilterInfo(i, NULL, 0, ach, sizeof(ach), szHandler, cb); i++)
  166. {
  167. if (lstrcmpi(ext+1, ach) == 0)
  168. break;
  169. else
  170. *szHandler = 0;
  171. }
  172. // if the handler file does not exist fail.
  173. if (*szHandler && GetFileAttributes(szHandler) != -1)
  174. f = TRUE;
  175. //if we cant find a handler hard code JPEG
  176. if (!f && lstrcmpi(ext,TEXT(".jpg")) == 0)
  177. {
  178. lstrcpy(szHandler, TEXT("JPEGIM32.FLT"));
  179. // lstrcpy(szHandler, TEXT("JPEG32.FLT"));
  180. f = TRUE;
  181. }
  182. //if we cant find a handler hard code PCX
  183. if (!f && lstrcmpi(ext, TEXT(".pcx")) == 0)
  184. {
  185. lstrcpy(szHandler, TEXT("PCXIMP32.FLT"));
  186. f = TRUE;
  187. }
  188. return f;
  189. }
  190. //
  191. // FindBitmapInfo
  192. //
  193. // find the DIB bitmap in a memory meta file...
  194. //
  195. LPBITMAPINFOHEADER FindBitmapInfo(LPMETAHEADER pmh)
  196. {
  197. LPMETARECORD pmr;
  198. for (pmr = (LPMETARECORD)((LPBYTE)pmh + pmh->mtHeaderSize*2);
  199. pmr < (LPMETARECORD)((LPBYTE)pmh + pmh->mtSize*2);
  200. pmr = (LPMETARECORD)((LPBYTE)pmr + pmr->rdSize*2))
  201. {
  202. switch (pmr->rdFunction)
  203. {
  204. case META_DIBBITBLT:
  205. return (LPBITMAPINFOHEADER)&(pmr->rdParm[8]);
  206. case META_DIBSTRETCHBLT:
  207. return (LPBITMAPINFOHEADER)&(pmr->rdParm[10]);
  208. case META_STRETCHDIB:
  209. return (LPBITMAPINFOHEADER)&(pmr->rdParm[11]);
  210. case META_SETDIBTODEV:
  211. return (LPBITMAPINFOHEADER)&(pmr->rdParm[9]);
  212. }
  213. }
  214. return NULL;
  215. }
  216. // add for new filter JPEG32.FLT
  217. static LPVOID lpWMFBits = NULL;
  218. //
  219. // FindBitmapInfoFromWMF
  220. //
  221. // retrieve metafile header
  222. //
  223. LPBITMAPINFOHEADER FindBitmapInfoFromWMF(GRPI* pict)
  224. {
  225. UINT uiSizeBuf = 0;
  226. LPBITMAPINFOHEADER lpbi = NULL;
  227. //get the size of the metafile associated with hMF...
  228. if ((uiSizeBuf = GetMetaFileBitsEx(pict->h, 0, NULL)))
  229. {
  230. //allocate buffer
  231. lpWMFBits = GlobalAllocPtr(GHND, uiSizeBuf);
  232. //get the bits of the Windows metafile associated with hMF...
  233. if (!lpWMFBits)
  234. {
  235. return NULL;
  236. }
  237. //make a local copy of it in our segment
  238. if ( GetMetaFileBitsEx(pict->h, uiSizeBuf, lpWMFBits))
  239. {
  240. lpbi = FindBitmapInfo((LPMETAHEADER)lpWMFBits);
  241. }
  242. }
  243. return (lpbi);
  244. }
  245. // end for new filter JPEG32.FLT
  246. //
  247. // LoadDIBFromFile
  248. //
  249. // load a image file using a image import filter.
  250. //
  251. HRESULT LoadDIBFromFile(IN LPCTSTR szFileName, IN BITMAP_AND_METAFILE_COMBO * pBitmapAndMetaFile)
  252. {
  253. HRESULT hr = S_OK;
  254. HMODULE hModule;
  255. FILESPEC fileSpec; // file to load
  256. GRPI pict;
  257. UINT rc; // return code
  258. HANDLE hPrefMem = NULL; // filter-supplied preferences
  259. UINT wFilterType; // 2 = graphics filter
  260. TCHAR szHandler[MAX_PATH]; // changed from 128 to MAX_PATH
  261. LPVOID lpMeta = NULL;
  262. #ifdef UNICODE
  263. TCHAR szFileNameW[MAX_PATH];
  264. #endif
  265. UINT (FAR PASCAL *GetFilterInfo)(short v, LPSTR szFilterExten,
  266. HANDLE FAR * fph1, HANDLE FAR * fph2);
  267. UINT (FAR PASCAL *ImportGR)(HDC hdc, FILESPEC FAR *lpfs,
  268. GRPI FAR *p, HANDLE hPref);
  269. pBitmapAndMetaFile->pBitmapInfoHeader = NULL;
  270. pBitmapAndMetaFile->hMetaFile = NULL;
  271. if (!GetHandlerForFile(szFileName, szHandler, sizeof(szHandler)))
  272. return hr;
  273. if (szHandler[0] == 0)
  274. return hr;
  275. TIMESTART(TEXT("LoadDIBFromFile"));
  276. hModule = LoadLibrary(szHandler);
  277. if (hModule == NULL)
  278. goto exit;
  279. /* get a pointer to the ImportGR function */
  280. (FARPROC)GetFilterInfo = GetProcAddress(hModule, "GetFilterInfo");
  281. (FARPROC)ImportGR = GetProcAddress(hModule, "ImportGr");
  282. if (GetFilterInfo == NULL)
  283. (FARPROC)GetFilterInfo = GetProcAddress(hModule, "GetFilterInfo@16");
  284. if (ImportGR == NULL)
  285. (FARPROC)ImportGR = GetProcAddress(hModule, "ImportGr@16");
  286. if (ImportGR == NULL)
  287. goto exit;
  288. if (GetFilterInfo != NULL)
  289. {
  290. wFilterType = (*GetFilterInfo)
  291. ((short) 2, // interface version no.
  292. (LPSTR)"", // end of .INI entry
  293. (HANDLE FAR *) &hPrefMem, // fill in: preferences
  294. (HANDLE FAR *) NULL); // unused in Windows
  295. /* the return value is the type of filter: 0=error,
  296. * 1=text-filter, 2=graphics-filter
  297. */
  298. if (wFilterType != 2)
  299. goto exit;
  300. }
  301. fileSpec.slippery = FALSE; // TRUE if file may disappear
  302. fileSpec.write = FALSE; // TRUE if open for write
  303. fileSpec.unnamed = FALSE; // TRUE if unnamed
  304. fileSpec.linked = FALSE; // Linked to an FS FCB
  305. fileSpec.mark = FALSE; // Generic mark bit
  306. ////fileSpec.fType = 0L; // The file type
  307. fileSpec.handle = 0; // MS-DOS open file handle
  308. fileSpec.filePos = 0L;
  309. //the converters need a pathname without spaces!
  310. #ifdef UNICODE
  311. GetShortPathName(szFileName, szFileNameW, ARRAYSIZE(szFileNameW));
  312. wcstombs(fileSpec.fullName, szFileNameW, ARRAYSIZE(fileSpec.fullName));
  313. #else
  314. GetShortPathName(szFileName, fileSpec.fullName, ARRAYSIZE(fileSpec.fullName));
  315. #endif
  316. pict.h = NULL;
  317. rc = (*ImportGR)
  318. (NULL, // "the target DC" (printer?)
  319. (FILESPEC FAR *) &fileSpec, // file to read
  320. (GRPI FAR *) &pict, // fill in: result metafile
  321. (HANDLE) hPrefMem); // preferences memory
  322. if (rc != 0 || pict.h == NULL)
  323. goto exit;
  324. //
  325. // find the BITMAPINFO in the returned metafile
  326. // this saves us from creating a metafile and duplicating
  327. // all the memory.
  328. //
  329. // add for new filter JPEG32.FLT
  330. lpMeta = GlobalLock(pict.h);
  331. rc = GetLastError();
  332. bVersion2 = (lpMeta) ? TRUE : FALSE;
  333. //
  334. // The whole "bversion2" logic above seems fundamentally flawed.
  335. // It is broken under NT, that's for certain. Since I have had
  336. // limited luck getting info on the graphics filter interface
  337. // and the "bversion2" logic, I am going to assume that for the
  338. // NT world we don't have a version2 filter.
  339. //
  340. if (IsPlatformNT()) bVersion2 = FALSE;
  341. if ( bVersion2 )
  342. {
  343. pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfo((LPMETAHEADER)lpMeta);
  344. }
  345. else
  346. {
  347. pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfoFromWMF(&pict);
  348. pBitmapAndMetaFile->pBitmapInfoHeader->biYPelsPerMeter = 0x12345678;
  349. }
  350. // pBitmapAndMetaFile->pBitmapInfoHeader = FindBitmapInfo((LPMETAHEADER)GlobalLock(pict.h));
  351. // add for new filter JPEG32.FLT
  352. if (pBitmapAndMetaFile->pBitmapInfoHeader == NULL) // cant find it bail
  353. {
  354. GlobalFree(pict.h);
  355. }
  356. else
  357. {
  358. // BUGBUG This will not work in Win64 - throwing away high 32 bits
  359. pBitmapAndMetaFile->hMetaFile = pict.h;
  360. }
  361. exit:
  362. if (hPrefMem != NULL)
  363. GlobalFree(hPrefMem);
  364. if (hModule)
  365. FreeLibrary(hModule);
  366. TIMESTOP(TEXT("LoadDIBFromFile"));
  367. return hr;
  368. }
  369. //
  370. // FreeDIB
  371. //
  372. void FreeDIB(BITMAP_AND_METAFILE_COMBO bam)
  373. {
  374. if (bam.pBitmapInfoHeader)
  375. {
  376. if (bam.hMetaFile && (bam.pBitmapInfoHeader->biYPelsPerMeter == 0x12345678))
  377. {
  378. // add for new filter JPEG32.FLT
  379. // GlobalFree((HANDLE)lpbi->biXPelsPerMeter);
  380. //done with the actual memory used to store bits so nuke it...
  381. if ( !bVersion2 )
  382. {
  383. if ( lpWMFBits )
  384. {
  385. // DSCHOTT 98JUL20
  386. // Moved this DeleteMetaFile() from after this
  387. // IF clause up to here since lpbi->biXPelsPerMeter
  388. // is not valid after this GlobalFreePtr() call.
  389. DeleteMetaFile(bam.hMetaFile);
  390. GlobalFreePtr(lpWMFBits);
  391. lpWMFBits = NULL;
  392. }
  393. // DSCHOTT moved up inside IF clause before GlobalFreePtr().
  394. // DeleteMetaFile((HMETAFILE)lpbi->biXPelsPerMeter);
  395. }
  396. else // bVersion2
  397. {
  398. GlobalFree(bam.hMetaFile);
  399. }
  400. // add for new filter JPEG32.FLT
  401. }
  402. else
  403. {
  404. GlobalFree(GlobalHandle(bam.pBitmapInfoHeader));
  405. }
  406. } // end if lpbi
  407. } // FreeDIB()
  408. #define DIVIDE_SAFE(nNumber) ((0 == (nNumber)) ? 1 : (nNumber))
  409. //
  410. // LoadImageFromFile
  411. //
  412. // load a image file using a image import filter.
  413. //
  414. HBITMAP LoadImageFromFile(LPCTSTR szFileName, BITMAP_AND_METAFILE_COMBO * pBitmapMetaFile, int width, int height, int bpp, int dither)
  415. {
  416. HBITMAP hbm=NULL;
  417. HBITMAP hbmT;
  418. HBITMAP hbmFree=NULL;
  419. HDC hdc=NULL;
  420. BITMAP_AND_METAFILE_COMBO bamFree = {0};
  421. HCURSOR hcur;
  422. LPBYTE pbSrc;
  423. LPBYTE pbDst;
  424. LPCTSTR ext;
  425. TCHAR ach[MAX_PATH]; //dschott changed from 128 to MAX_PATH
  426. int displaybpp;
  427. UINT rastercaps;
  428. DIBSECTION ds;
  429. struct {
  430. BITMAPINFOHEADER bi;
  431. DWORD ct[256];
  432. } dib;
  433. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  434. // TIMESTART(TEXT("LoadImageFromFile"));
  435. if (pBitmapMetaFile && (pBitmapMetaFile->pBitmapInfoHeader == NULL))
  436. {
  437. // find the extension
  438. ext = FindExtension(szFileName);
  439. // if it is a bitmap file no handler is needed, we can just call LoadImage
  440. if (lstrcmpi(ext,TEXT(".bmp")) == 0 ||
  441. lstrcmpi(ext,TEXT(".dib")) == 0 ||
  442. lstrcmpi(ext,TEXT(".rle")) == 0 ||
  443. ext[0] != TEXT('.'))
  444. {
  445. if (width < 0 && height < 0)
  446. {
  447. DWORD dw = GetImageTitle(szFileName, ach, sizeof(ach));
  448. width = (int)LOWORD(dw) * -width / DIVIDE_SAFE(GetSystemMetrics(SM_CXSCREEN));
  449. height = (int)HIWORD(dw) * -height / DIVIDE_SAFE(GetSystemMetrics(SM_CYSCREEN));
  450. }
  451. hbm = LoadImage(NULL, szFileName, IMAGE_BITMAP, width, height, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
  452. goto exit;
  453. }
  454. TIMESTART(TEXT("LoadDIBFromFile"));
  455. LoadDIBFromFile(szFileName, pBitmapMetaFile);
  456. bamFree.pBitmapInfoHeader = pBitmapMetaFile->pBitmapInfoHeader;
  457. bamFree.hMetaFile = pBitmapMetaFile->hMetaFile;
  458. TIMESTOP(TEXT("LoadDIBFromFile"));
  459. }
  460. if (pBitmapMetaFile == NULL) // cant find it bail
  461. goto exit;
  462. //
  463. // figure out the lpBits pointer we need to pass to StretchDIBits
  464. //
  465. pbSrc = (LPBYTE)pBitmapMetaFile->pBitmapInfoHeader + pBitmapMetaFile->pBitmapInfoHeader->biSize + pBitmapMetaFile->pBitmapInfoHeader->biClrUsed * sizeof(RGBQUAD);
  466. if (pBitmapMetaFile->pBitmapInfoHeader->biClrUsed == 0 && pBitmapMetaFile->pBitmapInfoHeader->biBitCount <= 8)
  467. pbSrc = (LPBYTE)((LPDWORD)pbSrc + (1 << pBitmapMetaFile->pBitmapInfoHeader->biBitCount));
  468. hdc = CreateCompatibleDC(NULL);
  469. if (hdc == NULL)
  470. goto exit;
  471. displaybpp = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
  472. rastercaps = GetDeviceCaps(hdc, RASTERCAPS);
  473. //
  474. // create a DIBSection and draw the DIB into it.
  475. // we need to figure out what type of DIBSection to
  476. // make. the caller can ask for a specific bit depth (bpp>0)
  477. // or the same bit depth as the image (bpp==0) or the bit depth
  478. // of the display (bpp==-1) the same goes for width/height
  479. //
  480. hmemcpy(&dib, pBitmapMetaFile->pBitmapInfoHeader, sizeof(dib));
  481. dib.bi.biClrUsed = 0;
  482. dib.bi.biXPelsPerMeter = 0;
  483. dib.bi.biYPelsPerMeter = 0;
  484. if (width < 0)
  485. width = dib.bi.biWidth * -width / DIVIDE_SAFE(GetSystemMetrics(SM_CXSCREEN));
  486. if (height < 0)
  487. height = dib.bi.biHeight * -height / DIVIDE_SAFE(GetSystemMetrics(SM_CYSCREEN));
  488. if (width > 0)
  489. dib.bi.biWidth = width;
  490. if (height > 0)
  491. dib.bi.biHeight = height;
  492. // get the best bit depth to use on this display.
  493. if (bpp == -1 && dib.bi.biBitCount > 8)
  494. {
  495. if (displaybpp > 8)
  496. bpp = 16;
  497. else
  498. bpp = 8;
  499. }
  500. // we may need to figure out a palette for this image
  501. //
  502. // if we can find a file with the same name and a extension of .PAL
  503. // use that as the palette, else use a default set of colors.
  504. //
  505. if (bpp == 8)
  506. {
  507. dib.bi.biBitCount = 8;
  508. dib.bi.biCompression = 0;
  509. if (pBitmapMetaFile->pBitmapInfoHeader->biBitCount > 8)
  510. {
  511. HDC screen;
  512. lstrcpy(ach, szFileName);
  513. lstrcpy((LPTSTR)FindExtension(ach),TEXT(".pal"));
  514. // LoadPaletteFromFile("") will give us back the HT colors...
  515. if (dither == DITHER_STANDARD ||
  516. dither == DITHER_STANDARD_HYBRID)
  517. {
  518. ach[0] = 0;
  519. }
  520. screen = GetDC(NULL);
  521. dib.bi.biClrUsed = LoadPaletteFromFile(ach, dib.ct,
  522. (rastercaps & RC_PALETTE) ? NULL : screen);
  523. ReleaseDC(NULL, screen);
  524. }
  525. }
  526. #if 0
  527. else if (bpp == 565)
  528. {
  529. dib.bi.biBitCount = 16;
  530. dib.bi.biCompression = BI_BITFIELDS;
  531. dib.ct[0] = 0x0000F800;
  532. dib.ct[1] = 0x000007E0;
  533. dib.ct[2] = 0x0000001F;
  534. }
  535. else if (bpp == 555)
  536. {
  537. dib.bi.biBitCount = 16;
  538. dib.bi.biCompression = 0;
  539. }
  540. #endif
  541. else if (bpp > 0)
  542. {
  543. dib.bi.biBitCount = (WORD)bpp;
  544. dib.bi.biCompression = 0;
  545. }
  546. //
  547. // check to see if we are dithering, and if we are also stretching
  548. // we need to do the stretching NOW so we dont end up stretching
  549. // dither patterns, we also do this before calling CreateDIBSection
  550. // to make the memory usage of this already piggy code smaller
  551. //
  552. if (dither && pBitmapMetaFile->pBitmapInfoHeader->biBitCount == 24 && (bpp == 16 || bpp == 8))
  553. {
  554. if (dib.bi.biWidth!=pBitmapMetaFile->pBitmapInfoHeader->biWidth || dib.bi.biHeight!=pBitmapMetaFile->pBitmapInfoHeader->biHeight)
  555. {
  556. // TIMESTART(TEXT("Stretch"));
  557. if (hbmFree = LoadImageFromFile(NULL, pBitmapMetaFile, dib.bi.biWidth, dib.bi.biHeight, 0, 0))
  558. {
  559. GetObject(hbmFree, sizeof(ds), &ds);
  560. pbSrc = ds.dsBm.bmBits;
  561. pBitmapMetaFile->pBitmapInfoHeader = &ds.dsBmih;
  562. if (bamFree.pBitmapInfoHeader != NULL)
  563. {
  564. FreeDIB(bamFree);
  565. bamFree.pBitmapInfoHeader = NULL;
  566. bamFree.hMetaFile = NULL;
  567. }
  568. }
  569. // TIMESTOP(TEXT("Stretch"));
  570. }
  571. }
  572. else
  573. {
  574. dither = 0;
  575. }
  576. // make the DIBSection what the caller wants.
  577. hbm = CreateDIBSection(hdc, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS, &pbDst, NULL, 0);
  578. if (hbm == NULL)
  579. goto exit;
  580. hbmT = SelectObject(hdc, hbm);
  581. SetStretchBltMode(hdc, COLORONCOLOR);
  582. if (dither)
  583. {
  584. TIMESTART(TEXT("Dithering"));
  585. if ((dither == DITHER_HALFTONE) && (dib.bi.biBitCount == 8))
  586. {
  587. HalftoneImage(hdc, hbm, pBitmapMetaFile->pBitmapInfoHeader, pbSrc);
  588. }
  589. else
  590. {
  591. DitherImage(hdc, hbm, pBitmapMetaFile->pBitmapInfoHeader, pbSrc, ((dib.bi.biBitCount == 16) ||
  592. ((dither != DITHER_STANDARD) && (dither != DITHER_CUSTOM))));
  593. }
  594. TIMESTOP(TEXT("Dithering"));
  595. }
  596. else
  597. {
  598. //
  599. // now draw the DIB into the DIBSection, GDI will handle all
  600. // the format conversion here.
  601. //
  602. TIMESTART(TEXT("StretchDIBits"));
  603. StretchDIBits(hdc,
  604. 0, 0, dib.bi.biWidth, dib.bi.biHeight,
  605. 0, 0, pBitmapMetaFile->pBitmapInfoHeader->biWidth, pBitmapMetaFile->pBitmapInfoHeader->biHeight,
  606. pbSrc, (LPBITMAPINFO)pBitmapMetaFile->pBitmapInfoHeader, DIB_RGB_COLORS, SRCCOPY);
  607. TIMESTOP(TEXT("StretchDIBits"));
  608. }
  609. SelectObject(hdc, hbmT);
  610. exit:
  611. if (hdc)
  612. DeleteDC(hdc);
  613. if (bamFree.pBitmapInfoHeader != NULL)
  614. FreeDIB(bamFree);
  615. if (hbmFree)
  616. DeleteObject(hbmFree);
  617. if (hcur)
  618. SetCursor(hcur);
  619. // TIMESTOP(TEXT("LoadImageFromFile"));
  620. return hbm;
  621. }
  622. //
  623. // LoadPaletteFromFile
  624. //
  625. DWORD LoadPaletteFromFile(LPCTSTR szFile, LPDWORD rgb, HDC hdcNearest)
  626. {
  627. HANDLE fh;
  628. DWORD dwBytesRead;
  629. UINT i;
  630. struct {
  631. DWORD dwRiff;
  632. DWORD dwFileSize;
  633. DWORD dwPal;
  634. DWORD dwData;
  635. DWORD dwDataSize;
  636. WORD palVersion;
  637. WORD palNumEntries;
  638. DWORD rgb[256];
  639. } pal;
  640. pal.dwRiff = 0;
  641. // read in the palette file.
  642. fh = CreateFile(szFile,
  643. GENERIC_READ,
  644. FILE_SHARE_READ | FILE_SHARE_WRITE,
  645. NULL,
  646. OPEN_EXISTING,
  647. FILE_ATTRIBUTE_NORMAL,
  648. NULL);
  649. if (fh != INVALID_HANDLE_VALUE)
  650. {
  651. if (!ReadFile(fh, (LPVOID)&pal, sizeof(pal), &dwBytesRead, NULL))
  652. {
  653. NULL; // We failed. We check later but this line appeases PREFIX.
  654. }
  655. CloseHandle(fh);
  656. }
  657. // if the file is not a palette file, or does not exist
  658. // default to the halftone colors.
  659. if (pal.dwRiff != 0x46464952 || // 'RIFF'
  660. pal.dwPal != 0x204C4150 || // 'PAL '
  661. pal.dwData != 0x61746164 || // 'data'
  662. pal.palVersion != 0x0300 ||
  663. pal.palNumEntries > 256 ||
  664. pal.palNumEntries < 1)
  665. {
  666. HPALETTE hpal = CreateHalftonePalette(NULL);
  667. if (hpal)
  668. {
  669. GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY)pal.rgb);
  670. DeleteObject(hpal);
  671. }
  672. pal.palNumEntries = 256;
  673. }
  674. for (i = 0; i < pal.palNumEntries; i++)
  675. {
  676. COLORREF c = pal.rgb[i];
  677. if (hdcNearest)
  678. c = GetNearestColor(hdcNearest, c);
  679. rgb[i] = RGB(GetBValue(c),GetGValue(c), GetRValue(c));
  680. }
  681. return pal.palNumEntries;
  682. }
  683. //
  684. // magic number we write to the file so we can make sure the
  685. // title string is realy there.
  686. //
  687. #define TITLE_MAGIC 0x47414D53
  688. //
  689. // SaveImageToFile
  690. //
  691. BOOL SaveImageToFile(HBITMAP hbm, LPCTSTR szFile, LPCTSTR szTitle)
  692. {
  693. BITMAPFILEHEADER hdr;
  694. HANDLE fh;
  695. DWORD dwBytesWritten;
  696. DWORD dw;
  697. HDC hdc;
  698. DIBSECTION dib;
  699. DWORD ct[256];
  700. #ifdef UNICODE
  701. CHAR szTitleA[MAX_PATH];
  702. UINT uCodePage;
  703. #endif
  704. if (GetObject(hbm, sizeof(dib), &dib) == 0)
  705. return FALSE;
  706. if (dib.dsBm.bmBits == NULL)
  707. return FALSE;
  708. hdc = CreateCompatibleDC(NULL);
  709. SelectObject(hdc, hbm);
  710. if (dib.dsBmih.biBitCount <= 8)
  711. {
  712. dib.dsBmih.biClrUsed = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)ct);
  713. }
  714. else if (dib.dsBmih.biCompression == BI_BITFIELDS)
  715. {
  716. dib.dsBmih.biClrUsed = 3;
  717. ct[0] = dib.dsBitfields[0];
  718. ct[1] = dib.dsBitfields[1];
  719. ct[2] = dib.dsBitfields[2];
  720. }
  721. DeleteDC(hdc);
  722. fh = CreateFile(szFile,
  723. GENERIC_READ | GENERIC_WRITE,
  724. FILE_SHARE_READ,
  725. NULL,
  726. CREATE_ALWAYS,
  727. FILE_ATTRIBUTE_NORMAL,
  728. NULL);
  729. if (fh == INVALID_HANDLE_VALUE)
  730. return FALSE;
  731. dw = sizeof(BITMAPFILEHEADER) +
  732. dib.dsBmih.biSize +
  733. dib.dsBmih.biClrUsed * sizeof(RGBQUAD) +
  734. dib.dsBmih.biSizeImage;
  735. hdr.bfType = 0x4d42; // BFT_BITMAP
  736. hdr.bfSize = dw;
  737. hdr.bfReserved1 = 0;
  738. hdr.bfReserved2 = 0;
  739. hdr.bfOffBits = dw - dib.dsBmih.biSizeImage;
  740. #define WRITE(fh, p, cb) if (!WriteFile(fh, (LPVOID)(p), cb, &dwBytesWritten, NULL)) goto error;
  741. WRITE(fh,&hdr,sizeof(BITMAPFILEHEADER));
  742. WRITE(fh,&dib.dsBmih,dib.dsBmih.biSize);
  743. WRITE(fh,&ct,dib.dsBmih.biClrUsed * sizeof(RGBQUAD));
  744. WRITE(fh,dib.dsBm.bmBits, dib.dsBmih.biSizeImage);
  745. if (szTitle && *szTitle)
  746. {
  747. dw = TITLE_MAGIC;
  748. WRITE(fh,&dw, sizeof(dw));
  749. #ifdef UNICODE
  750. // Need to convert the title string to ANSI before writing it
  751. // to the file
  752. uCodePage = _getmbcp();
  753. WideCharToMultiByte(uCodePage, 0, szTitle, -1,
  754. szTitleA, MAX_PATH, NULL, NULL);
  755. dw = lstrlenA(szTitleA)+1;
  756. WRITE(fh,&dw, sizeof(dw));
  757. WRITE(fh,szTitleA,dw);
  758. #else
  759. // No Unicode so no need to convert to ANSI
  760. dw = SZSIZEINBYTES(szTitle)+1;
  761. WRITE(fh,&dw, sizeof(dw));
  762. WRITE(fh,szTitle,dw);
  763. #endif
  764. }
  765. CloseHandle(fh);
  766. return TRUE;
  767. error:
  768. CloseHandle(fh);
  769. DeleteFile(szFile);
  770. return FALSE;
  771. }
  772. DWORD GetImageTitle(LPCTSTR szFile, LPTSTR szTitle, UINT cb)
  773. {
  774. BITMAPFILEHEADER hdr;
  775. BITMAPINFOHEADER bi;
  776. HANDLE fh;
  777. DWORD dwBytesRead;
  778. DWORD dw=0;
  779. CHAR szTitleA[MAX_PATH];
  780. #ifdef UNICODE
  781. UINT uCodePage;
  782. #endif
  783. fh = CreateFile(szFile,
  784. GENERIC_READ,
  785. FILE_SHARE_READ | FILE_SHARE_WRITE,
  786. NULL,
  787. OPEN_EXISTING,
  788. FILE_ATTRIBUTE_NORMAL,
  789. NULL);
  790. if (fh == INVALID_HANDLE_VALUE)
  791. return FALSE;
  792. dwBytesRead = 0;
  793. ReadFile(fh, (LPVOID)&hdr, sizeof(hdr), &dwBytesRead, NULL);
  794. if (dwBytesRead != sizeof(hdr))
  795. {
  796. goto error;
  797. }
  798. if (hdr.bfType != 0x4d42) // BFT_BITMAP
  799. goto error;
  800. if (hdr.bfSize == 0)
  801. goto error;
  802. dwBytesRead = 0;
  803. if (!ReadFile(fh, (LPVOID)&bi, sizeof(bi), &dwBytesRead, NULL) ||
  804. (dwBytesRead != sizeof(bi)))
  805. {
  806. goto error;
  807. }
  808. if (bi.biSize != sizeof(bi))
  809. goto error;
  810. SetFilePointer(fh, hdr.bfSize, NULL, FILE_BEGIN);
  811. dwBytesRead=0;
  812. ReadFile(fh, (LPVOID)&dw, sizeof(dw), &dwBytesRead, NULL);
  813. if (dw != TITLE_MAGIC)
  814. goto error;
  815. dwBytesRead=0;
  816. ReadFile(fh, (LPVOID)&dw, sizeof(dw), &dwBytesRead, NULL);
  817. if ((dw > cb) || (dwBytesRead != sizeof(dw)))
  818. goto error;
  819. dwBytesRead=0;
  820. ReadFile(fh, (LPVOID)szTitleA, dw, &dwBytesRead, NULL);
  821. if (dwBytesRead != dw)
  822. goto error;
  823. #ifdef UNICODE
  824. // Need to convert the ANSI string to UNICODE.
  825. uCodePage = _getmbcp();
  826. MultiByteToWideChar(uCodePage, 0, szTitleA, -1, szTitle, MAX_PATH);
  827. #else
  828. // String should be ANSI, no conversion needed, just copy it to
  829. // the destination buffer.
  830. lstrcpy(szTitle, szTitleA);
  831. #endif
  832. CloseHandle(fh);
  833. return MAKELONG(bi.biWidth, bi.biHeight);
  834. error:
  835. CloseHandle(fh);
  836. return MAKELONG(bi.biWidth, bi.biHeight);
  837. }
  838. //
  839. // CacheLoadImageFromFile
  840. //
  841. static HBITMAP _hbm;
  842. static int _width;
  843. static int _height;
  844. static int _bpp;
  845. static int _dither;
  846. static BITMAP_AND_METAFILE_COMBO _dib;
  847. static TCHAR _name[MAX_PATH];
  848. HBITMAP CacheLoadImageFromFile(LPCTSTR szFileName, int width, int height, int bpp, int dither)
  849. {
  850. TIMESTART(TEXT("CacheLoadImageFromFile"));
  851. if (szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".bmp")) == 0)
  852. return LoadImageFromFile(szFileName, NULL, width, height, bpp, dither);
  853. // If it's an HTML file use IThumbnail to create a bmp
  854. if ((szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".htm")) == 0) ||
  855. (szFileName && lstrcmpi(FindExtension(szFileName),TEXT(".html")) == 0))
  856. {
  857. SetCursor(LoadCursor(NULL, IDC_WAIT));
  858. return HtmlToBmp(szFileName, width, height);
  859. }
  860. //
  861. // check our cache.
  862. //
  863. if (szFileName &&
  864. _hbm != NULL &&
  865. _width == width &&
  866. _height == height &&
  867. _bpp == bpp &&
  868. _dither == dither &&
  869. lstrcmpi(szFileName, _name) == 0)
  870. {
  871. return _hbm;
  872. }
  873. if (_hbm)
  874. {
  875. DeleteObject(_hbm);
  876. _hbm = NULL;
  877. }
  878. if (_dib.pBitmapInfoHeader == NULL || szFileName == NULL || lstrcmpi(szFileName, _name) != 0)
  879. {
  880. if (_dib.pBitmapInfoHeader)
  881. {
  882. FreeDIB(_dib);
  883. _dib.pBitmapInfoHeader = NULL;
  884. _dib.hMetaFile = NULL;
  885. }
  886. if (szFileName == NULL)
  887. return NULL;
  888. LoadDIBFromFile(szFileName, &_dib);
  889. lstrcpy(_name, szFileName);
  890. }
  891. if (_dib.pBitmapInfoHeader == NULL)
  892. return NULL;
  893. _hbm = LoadImageFromFile(szFileName, &_dib, width, height, bpp, dither);
  894. if (_hbm)
  895. {
  896. _width = width;
  897. _height = height;
  898. _bpp = bpp;
  899. _dither = dither;
  900. }
  901. TIMESTOP(TEXT("CacheLoadImageFromFile"));
  902. return _hbm;
  903. }
  904. void CacheDeleteBitmap(HBITMAP hbm)
  905. {
  906. #if 0
  907. //
  908. // we are already caching the DIB data in memory, so we dont need to cache
  909. // the bitmap
  910. //
  911. DeleteObject(hbm);
  912. if (hbm == _hbm)
  913. _hbm = NULL;
  914. #else
  915. if (hbm != _hbm)
  916. DeleteObject(hbm);
  917. #endif
  918. }
  919. #ifdef _CONSOLE
  920. #ifndef UNICODE // This console stuff is not UNICODE smart.
  921. #include <stdio.h>
  922. void main (int argc, char **argv)
  923. {
  924. HBITMAP hbm;
  925. int bpp=-1; // default to screen.
  926. char ach[128];
  927. argv++;
  928. argc--;
  929. if (argc < 1)
  930. {
  931. printf("usage: %s [-8 -555 -565 -24 -32] input.jpg output.bmp\n", argv[-1]);
  932. exit(-1);
  933. }
  934. while (argc > 0 && **argv == '-')
  935. {
  936. if (lstrcmp(*argv, "-8") == 0) bpp = 8;
  937. if (lstrcmp(*argv, "-16") == 0) bpp = 16;
  938. if (lstrcmp(*argv, "-555") == 0) bpp = 555;
  939. if (lstrcmp(*argv, "-565") == 0) bpp = 565;
  940. if (lstrcmp(*argv, "-24") == 0) bpp = 24;
  941. if (lstrcmp(*argv, "-32") == 0) bpp = 32;
  942. argc--;
  943. argv++;
  944. }
  945. printf("Loading %s....\n", argv[0]);
  946. hbm = LoadImageFromFile(argv[0], 0, 0, bpp);
  947. if (hbm == NULL)
  948. {
  949. printf("can't load %s\n", argv[0]);
  950. exit(-1);
  951. }
  952. if (argc > 1)
  953. {
  954. BITMAP bm;
  955. GetObject(hbm, sizeof(bm), &bm);
  956. printf("Writing %d bpp image %s....\n", bm.bmBitsPixel, argv[1]);
  957. if (!SaveImageToFile(hbm, argv[1], argv[0]))
  958. {
  959. printf("can't save %s\n", argv[1]);
  960. exit(-1);
  961. }
  962. GetImageTitle(argv[1], ach, sizeof(ach));
  963. printf("image title: %s\n", ach);
  964. }
  965. exit(0);
  966. }
  967. #endif // !UNICODE
  968. #endif // _CONSOLE