Windows NT 4.0 source code leak
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.

496 lines
17 KiB

4 years ago
  1. /******************************Module*Header*******************************\
  2. * Module Name: dib.c
  3. *
  4. * (Brief description)
  5. *
  6. * Created: 21-Feb-1994 23:12:58
  7. * Author: Gilman Wong [gilmanw]
  8. *
  9. * Copyright (c) 1994 Microsoft Corporation
  10. *
  11. * (General description of its use)
  12. *
  13. * Dependencies:
  14. *
  15. * (#defines)
  16. * (#includes)
  17. *
  18. \**************************************************************************/
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include "tk.h"
  24. #define static
  25. #define BFT_BITMAP 0x4d42 // 'BM' -- indicates structure is BITMAPFILEHEADER
  26. // struct BITMAPFILEHEADER {
  27. // WORD bfType
  28. // DWORD bfSize
  29. // WORD bfReserved1
  30. // WORD bfReserved2
  31. // DWORD bfOffBits
  32. // }
  33. #define OFFSET_bfType 0
  34. #define OFFSET_bfSize 2
  35. #define OFFSET_bfReserved1 6
  36. #define OFFSET_bfReserved2 8
  37. #define OFFSET_bfOffBits 10
  38. #define SIZEOF_BITMAPFILEHEADER 14
  39. // Read a WORD-aligned DWORD. Needed because BITMAPFILEHEADER has
  40. // WORD-alignment.
  41. #define READDWORD(pv) ( (DWORD)((PWORD)(pv))[0] \
  42. | ((DWORD)((PWORD)(pv))[1] << 16) ) \
  43. // Computes the number of BYTES needed to contain n number of bits.
  44. #define BITS2BYTES(n) ( ((n) + 7) >> 3 )
  45. /****************************************************************************
  46. * *
  47. * FUNCTION : DibNumColors(VOID FAR * pv) *
  48. * *
  49. * PURPOSE : Determines the number of colors in the DIB by looking at *
  50. * the BitCount filed in the info block. *
  51. * *
  52. * RETURNS : The number of colors in the DIB. *
  53. * *
  54. * Stolen from SDK ShowDIB example. *
  55. ****************************************************************************/
  56. WORD DibNumColors(VOID FAR * pv)
  57. {
  58. WORD bits;
  59. BITMAPINFOHEADER UNALIGNED *lpbi;
  60. BITMAPCOREHEADER UNALIGNED *lpbc;
  61. lpbi = ((LPBITMAPINFOHEADER)pv);
  62. lpbc = ((LPBITMAPCOREHEADER)pv);
  63. /* With the BITMAPINFO format headers, the size of the palette
  64. * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  65. * is dependent on the bits per pixel ( = 2 raised to the power of
  66. * bits/pixel).
  67. *
  68. * Because of the way we use this call, BITMAPINFOHEADER may be out
  69. * of alignment if it follows a BITMAPFILEHEADER. So use the macro
  70. * to safely access DWORD fields.
  71. */
  72. if (READDWORD(&lpbi->biSize) != sizeof(BITMAPCOREHEADER)){
  73. if (READDWORD(&lpbi->biClrUsed) != 0)
  74. {
  75. return (WORD) READDWORD(&lpbi->biClrUsed);
  76. }
  77. bits = lpbi->biBitCount;
  78. }
  79. else
  80. bits = lpbc->bcBitCount;
  81. switch (bits){
  82. case 1:
  83. return 2;
  84. case 4:
  85. return 16;
  86. case 8:
  87. return 256;
  88. default:
  89. /* A 24 bitcount DIB has no color table */
  90. return 0;
  91. }
  92. }
  93. /******************************Public*Routine******************************\
  94. * tkDIBImageLoad
  95. *
  96. * ANSI version stub. Only here for orthogonality with tkRGBImageLoad.
  97. *
  98. * History:
  99. * 22-Feb-1994 -by- Gilman Wong [gilmanw]
  100. * Wrote it.
  101. \**************************************************************************/
  102. TK_RGBImageRec *tkDIBImageLoadAW(char *fileName, BOOL bUnicode);
  103. TK_RGBImageRec *tkDIBImageLoad(char *fileName)
  104. {
  105. return tkDIBImageLoadAW(fileName, FALSE);
  106. }
  107. /******************************Public*Routine******************************\
  108. * tkDIBImageLoadAW
  109. *
  110. * Loads a DIB file (specified as either an ANSI or Unicode filename,
  111. * depending on the bUnicode flag) and converts it into a TK image format.
  112. *
  113. * The technique used is based on CreateDIBSection and SetDIBits.
  114. * CreateDIBSection is used to create a DIB with a format easily converted
  115. * into the TK image format (packed 24BPP RGB). The only conversion
  116. * required is swapping R and B in each RGB triplet (see history below)
  117. * The resulting bitmap is selected into a memory DC.
  118. *
  119. * The DIB file is mapped into memory and SetDIBits called to initialize
  120. * the memory DC bitmap. It is during this step that GDI converts the
  121. * arbitrary DIB file format to RGB format.
  122. *
  123. * Finally, the RGB data in the DIB section is read out and repacked
  124. * as 24BPP 'BGR'.
  125. *
  126. * Returns:
  127. * Pointer to TK_RGBImageRec. If an error occurs, a diagnostic error
  128. * message is put into the error stream and tkQuit() is called,
  129. * terminating the app.
  130. *
  131. * History:
  132. * - 22-Feb-1994 -by- Gilman Wong [gilmanw]
  133. * Wrote it.
  134. *
  135. * - 01-May-1995 : [marcfo]
  136. * Don't quit if can't open DIB file - return NULL.
  137. *
  138. * - 27-Jul-1995 : [marcfo]
  139. * Changed CreateDIBSection to create an RGB mapping, so this would work
  140. * on win95. Swapping of R and B required, to generate BGR (R=low byte)
  141. * for GL. If the GL 'BGR' (R=high byte) extension becomes part of api
  142. * in OpenGL 2.0, then we can avoid swap and do a memcpy to grab the bits.
  143. *
  144. \**************************************************************************/
  145. TK_RGBImageRec *tkDIBImageLoadAW(char *fileName, BOOL bUnicode)
  146. {
  147. TK_RGBImageRec *final = (TK_RGBImageRec *) NULL; // Ptr to TK image struct
  148. // to return. Non-NULL
  149. // only for success.
  150. WORD wNumColors; // Number of colors in color table
  151. BITMAPFILEHEADER *pbmf; // Ptr to file header
  152. BITMAPINFOHEADER UNALIGNED *pbmihFile;
  153. BITMAPCOREHEADER UNALIGNED *pbmchFile; // Ptr to file's core header (if it exists)
  154. PVOID pvBitsFile; // Ptr to bitmap bits in file
  155. PBYTE pjBitsRGB; // Ptr to 24BPP RGB image in DIB section
  156. PBYTE pjTKBits = (PBYTE) NULL; // Ptr to final TK image bits
  157. PBYTE pjSrc; // Ptr to image file used for conversion
  158. PBYTE pjDst; // Ptr to TK image used for conversion
  159. // These need to be cleaned up when we exit:
  160. HANDLE hFile = INVALID_HANDLE_VALUE; // File handle
  161. HANDLE hMap = (HANDLE) NULL; // Mapping object handle
  162. PVOID pvFile = (PVOID) NULL; // Ptr to mapped file
  163. HDC hdcMem = (HDC) NULL; // 24BPP mem DC
  164. HBITMAP hbmRGB = (HBITMAP) NULL; // 24BPP RGB bitmap
  165. BITMAPINFO *pbmiSource = (BITMAPINFO *) NULL; // Ptr to source BITMAPINFO
  166. BITMAPINFO *pbmiRGB = (BITMAPINFO *) NULL; // Ptr to file's BITMAPINFO
  167. int i, j;
  168. int padBytes;
  169. // Map the DIB file into memory.
  170. hFile = bUnicode ?
  171. CreateFileW((LPWSTR) fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  172. OPEN_EXISTING, 0, 0) :
  173. CreateFileA((LPSTR) fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  174. OPEN_EXISTING, 0, 0);
  175. if (hFile == INVALID_HANDLE_VALUE)
  176. goto tkDIBLoadImage_cleanup;
  177. hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  178. if (!hMap)
  179. goto tkDIBLoadImage_cleanup;
  180. pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  181. if (!pvFile)
  182. goto tkDIBLoadImage_cleanup;
  183. // Check the file header. If the BFT_BITMAP magic number is there,
  184. // then the file format is a BITMAPFILEHEADER followed immediately
  185. // by either a BITMAPINFOHEADER or a BITMAPCOREHEADER. The bitmap
  186. // bits, in this case, are located at the offset bfOffBits from the
  187. // BITMAPFILEHEADER.
  188. //
  189. // Otherwise, this may be a raw BITMAPINFOHEADER or BITMAPCOREHEADER
  190. // followed immediately with the color table and the bitmap bits.
  191. pbmf = (BITMAPFILEHEADER *) pvFile;
  192. if ( pbmf->bfType == BFT_BITMAP )
  193. {
  194. pbmihFile = (BITMAPINFOHEADER *) ((PBYTE) pbmf + SIZEOF_BITMAPFILEHEADER);
  195. // BITMAPFILEHEADER is WORD aligned, so use safe macro to read DWORD
  196. // bfOffBits field.
  197. pvBitsFile = (PVOID *) ((PBYTE) pbmf
  198. + READDWORD((PBYTE) pbmf + OFFSET_bfOffBits));
  199. }
  200. else
  201. {
  202. pbmihFile = (BITMAPINFOHEADER *) pvFile;
  203. // Determination of where the bitmaps bits are needs to wait until we
  204. // know for sure whether we have a BITMAPINFOHEADER or a BITMAPCOREHEADER.
  205. }
  206. // Determine the number of colors in the DIB palette. This is non-zero
  207. // only for 8BPP or less.
  208. wNumColors = DibNumColors(pbmihFile);
  209. // Create a BITMAPINFO (with color table) for the DIB file. Because the
  210. // file may not have one (BITMAPCORE case) and potential alignment problems,
  211. // we will create a new one in memory we allocate.
  212. //
  213. // We distinguish between BITMAPINFO and BITMAPCORE cases based upon
  214. // BITMAPINFOHEADER.biSize.
  215. pbmiSource = (BITMAPINFO *)
  216. LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFO)
  217. + wNumColors * sizeof(RGBQUAD));
  218. if (!pbmiSource)
  219. {
  220. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  221. goto tkDIBLoadImage_cleanup;
  222. }
  223. // Note: need to use safe READDWORD macro because pbmihFile may
  224. // have only WORD alignment if it follows a BITMAPFILEHEADER.
  225. switch (READDWORD(&pbmihFile->biSize))
  226. {
  227. case sizeof(BITMAPINFOHEADER):
  228. // Convert WORD-aligned BITMAPINFOHEADER to aligned BITMAPINFO.
  229. pbmiSource->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  230. pbmiSource->bmiHeader.biWidth = READDWORD(&pbmihFile->biWidth);
  231. pbmiSource->bmiHeader.biHeight = READDWORD(&pbmihFile->biHeight);
  232. pbmiSource->bmiHeader.biPlanes = pbmihFile->biPlanes;
  233. pbmiSource->bmiHeader.biBitCount = pbmihFile->biBitCount;
  234. pbmiSource->bmiHeader.biCompression =
  235. READDWORD(&pbmihFile->biCompression);
  236. pbmiSource->bmiHeader.biSizeImage =
  237. READDWORD(&pbmihFile->biSizeImage);
  238. pbmiSource->bmiHeader.biXPelsPerMeter =
  239. READDWORD(&pbmihFile->biXPelsPerMeter);
  240. pbmiSource->bmiHeader.biYPelsPerMeter =
  241. READDWORD(&pbmihFile->biYPelsPerMeter);
  242. pbmiSource->bmiHeader.biClrUsed =
  243. READDWORD(&pbmihFile->biClrUsed);
  244. pbmiSource->bmiHeader.biClrImportant =
  245. READDWORD(&pbmihFile->biClrImportant);
  246. // Copy color table. It immediately follows the BITMAPINFOHEADER.
  247. memcpy((PVOID) &pbmiSource->bmiColors[0], (PVOID) (pbmihFile + 1),
  248. wNumColors * sizeof(RGBQUAD));
  249. // If we haven't already determined the position of the image bits,
  250. // we may now assume that they immediately follow the color table.
  251. if (!pvBitsFile)
  252. pvBitsFile = (PVOID) ((PBYTE) (pbmihFile + 1)
  253. + wNumColors * sizeof(RGBQUAD));
  254. break;
  255. case sizeof(BITMAPCOREHEADER):
  256. pbmchFile = (BITMAPCOREHEADER *) pbmihFile;
  257. // Convert BITMAPCOREHEADER to BITMAPINFOHEADER.
  258. pbmiSource->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  259. pbmiSource->bmiHeader.biWidth = (DWORD) pbmchFile->bcWidth;
  260. pbmiSource->bmiHeader.biHeight = (DWORD) pbmchFile->bcHeight;
  261. pbmiSource->bmiHeader.biPlanes = pbmchFile->bcPlanes;
  262. pbmiSource->bmiHeader.biBitCount = pbmchFile->bcBitCount;
  263. pbmiSource->bmiHeader.biCompression = BI_RGB;
  264. pbmiSource->bmiHeader.biSizeImage = 0;
  265. pbmiSource->bmiHeader.biXPelsPerMeter = 0;
  266. pbmiSource->bmiHeader.biYPelsPerMeter = 0;
  267. pbmiSource->bmiHeader.biClrUsed = wNumColors;
  268. pbmiSource->bmiHeader.biClrImportant = wNumColors;
  269. // Convert RGBTRIPLE color table into RGBQUAD color table.
  270. {
  271. RGBQUAD *rgb4 = pbmiSource->bmiColors;
  272. RGBTRIPLE *rgb3 = (RGBTRIPLE *) (pbmchFile + 1);
  273. for (i = 0; i < wNumColors; i++)
  274. {
  275. rgb4->rgbRed = rgb3->rgbtRed ;
  276. rgb4->rgbGreen = rgb3->rgbtGreen;
  277. rgb4->rgbBlue = rgb3->rgbtBlue ;
  278. rgb4->rgbReserved = 0;
  279. rgb4++;
  280. rgb3++;
  281. }
  282. }
  283. // If we haven't already determined the position of the image bits,
  284. // we may now assume that they immediately follow the color table.
  285. if (!pvBitsFile)
  286. pvBitsFile = (PVOID) ((PBYTE) (pbmihFile + 1)
  287. + wNumColors * sizeof(RGBTRIPLE));
  288. break;
  289. default:
  290. MESSAGEBOX(GetFocus(), "Unknown DIB file format.", "Error", MB_OK);
  291. goto tkDIBLoadImage_cleanup;
  292. }
  293. // Fill in default values (for fields that can have defaults).
  294. if (pbmiSource->bmiHeader.biSizeImage == 0)
  295. pbmiSource->bmiHeader.biSizeImage =
  296. BITS2BYTES( (DWORD) pbmiSource->bmiHeader.biWidth *
  297. pbmiSource->bmiHeader.biBitCount ) *
  298. pbmiSource->bmiHeader.biHeight;
  299. if (pbmiSource->bmiHeader.biClrUsed == 0)
  300. pbmiSource->bmiHeader.biClrUsed = wNumColors;
  301. // Create memory DC.
  302. hdcMem = CreateCompatibleDC(NULL);
  303. if (!hdcMem) {
  304. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  305. goto tkDIBLoadImage_cleanup;
  306. }
  307. // Create a 24BPP RGB DIB section and select it into the memory DC.
  308. pbmiRGB = (BITMAPINFO *)
  309. LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(BITMAPINFO) );
  310. if (!pbmiRGB)
  311. {
  312. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  313. goto tkDIBLoadImage_cleanup;
  314. }
  315. pbmiRGB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  316. pbmiRGB->bmiHeader.biWidth = pbmiSource->bmiHeader.biWidth;
  317. pbmiRGB->bmiHeader.biHeight = pbmiSource->bmiHeader.biHeight;
  318. pbmiRGB->bmiHeader.biPlanes = 1;
  319. pbmiRGB->bmiHeader.biBitCount = 24;
  320. pbmiRGB->bmiHeader.biCompression = BI_RGB;
  321. pbmiRGB->bmiHeader.biSizeImage = pbmiRGB->bmiHeader.biWidth
  322. * abs(pbmiRGB->bmiHeader.biHeight) * 3;
  323. hbmRGB = CreateDIBSection(hdcMem, pbmiRGB, DIB_RGB_COLORS,
  324. (PVOID *) &pjBitsRGB, NULL, 0);
  325. if (!hbmRGB)
  326. {
  327. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  328. goto tkDIBLoadImage_cleanup;
  329. }
  330. if (!SelectObject(hdcMem, hbmRGB))
  331. {
  332. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  333. goto tkDIBLoadImage_cleanup;
  334. }
  335. // Slam the DIB file image into the memory DC. GDI will do the work of
  336. // translating whatever format the DIB file has into RGB format.
  337. if (!SetDIBits(hdcMem, hbmRGB, 0, pbmiSource->bmiHeader.biHeight,
  338. pvBitsFile, pbmiSource, DIB_RGB_COLORS))
  339. {
  340. MESSAGEBOX(GetFocus(), "Image file conversion error.", "Error", MB_OK);
  341. goto tkDIBLoadImage_cleanup;
  342. }
  343. GdiFlush(); // make sure that SetDIBits executes
  344. // Convert to TK image format (packed RGB format).
  345. // Allocate with malloc to be consistent with tkRGBImageLoad (i.e., app
  346. // can deallocate with free()).
  347. pjTKBits = (PBYTE) malloc(pbmiRGB->bmiHeader.biSizeImage);
  348. if (!pjTKBits)
  349. {
  350. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  351. goto tkDIBLoadImage_cleanup;
  352. }
  353. pjSrc = pjBitsRGB;
  354. pjDst = pjTKBits;
  355. // src lines end on LONG boundary - so need to skip over any padding bytes
  356. padBytes = pbmiSource->bmiHeader.biWidth % sizeof(LONG);
  357. for (i = 0; i < pbmiSource->bmiHeader.biHeight; i++)
  358. {
  359. for (j = 0; j < pbmiSource->bmiHeader.biWidth; j++)
  360. {
  361. // swap R and B
  362. *pjDst++ = pjSrc[2];
  363. *pjDst++ = pjSrc[1];
  364. *pjDst++ = pjSrc[0];
  365. pjSrc += 3;
  366. }
  367. pjSrc += padBytes;
  368. }
  369. // Allocate and initialize the TK_RGBImageRec.
  370. // Allocate with malloc to be consistent with tkRGBImageLoad (i.e., app
  371. // can deallocate with free()).
  372. final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
  373. if (final == NULL) {
  374. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  375. goto tkDIBLoadImage_cleanup;
  376. }
  377. // If we get to here, we have suceeded!
  378. final->sizeX = pbmiSource->bmiHeader.biWidth;
  379. final->sizeY = pbmiSource->bmiHeader.biHeight;
  380. final->data = pjTKBits;
  381. // Cleanup objects.
  382. tkDIBLoadImage_cleanup:
  383. {
  384. if (hdcMem)
  385. DeleteDC(hdcMem);
  386. if (hbmRGB)
  387. DeleteObject(hbmRGB);
  388. if (pbmiRGB)
  389. LocalFree(pbmiRGB);
  390. if (pbmiSource)
  391. LocalFree(pbmiSource);
  392. if (pvFile)
  393. UnmapViewOfFile(pvFile);
  394. if (hMap)
  395. CloseHandle(hMap);
  396. if (hFile != INVALID_HANDLE_VALUE)
  397. CloseHandle(hFile);
  398. }
  399. // Check for error.
  400. if (!final)
  401. {
  402. if (pjTKBits)
  403. free(pjTKBits);
  404. if ( (hFile == INVALID_HANDLE_VALUE) || !hMap || !pvFile )
  405. {
  406. CHAR ach[256];
  407. bUnicode ? wsprintf(ach, "Failed to open DIB file %ws.\n", fileName) :
  408. wsprintf(ach, "Failed to open DIB file %s.\n", fileName);
  409. MESSAGEBOX(GetFocus(), ach, "Error", MB_OK);
  410. }
  411. }
  412. return final;
  413. }