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.

478 lines
14 KiB

  1. /*****************************************************************************
  2. *
  3. * CrunchDIB - shrink a DIB down by 2 with color averaging
  4. *
  5. *****************************************************************************/
  6. #define _WINDOWS
  7. #include <windows.h>
  8. #include <windowsx.h>
  9. #include <win32.h>
  10. #include <memory.h>
  11. //
  12. // support huge >64k DIBs?
  13. //
  14. #ifndef WIN32
  15. #define HUGE_DIBS
  16. #endif
  17. #ifdef HUGE_DIBS
  18. #define LPBYTE BYTE _huge *
  19. #define LPWORD WORD _huge *
  20. #define FAR _huge
  21. #endif
  22. /*****************************************************************************
  23. *
  24. * These are the standard VGA colors, we will be stuck with until the
  25. * end of time!
  26. *
  27. *****************************************************************************/
  28. static DWORD VGAColors[16] = {
  29. 0x00000000 // 0000 black
  30. ,0x00800000 // 0001 dark red
  31. ,0x00008000 // 0010 dark green
  32. ,0x00808000 // 0011 mustard
  33. ,0x00000080 // 0100 dark blue
  34. ,0x00800080 // 0101 purple
  35. ,0x00008080 // 0110 dark turquoise
  36. ,0x00C0C0C0 // 1000 gray
  37. ,0x00808080 // 0111 dark gray
  38. ,0x00FF0000 // 1001 red
  39. ,0x0000FF00 // 1010 green
  40. ,0x00FFFF00 // 1011 yellow
  41. ,0x000000FF // 1100 blue
  42. ,0x00FF00FF // 1101 pink (magenta)
  43. ,0x0000FFFF // 1110 cyan
  44. ,0x00FFFFFF // 1111 white
  45. };
  46. /*****************************************************************************
  47. *
  48. * bit(b,n) - get the Nth bit of BYTE b
  49. *
  50. *****************************************************************************/
  51. #define bit(b,n) (BYTE)(((b) & (1 << (n))) >> (n))
  52. /*****************************************************************************
  53. *
  54. * SumMono
  55. *
  56. * this routine taks four "mono" values and returns the average value.
  57. *
  58. * ((b0) + (b1) + (b2) + (b3) >= 2)
  59. *
  60. *
  61. *****************************************************************************/
  62. #define SumMono(b0,b1,b2,b3) (BYTE)(((b0) + (b1) + (b2) + (b3) + 2) / 4)
  63. /*****************************************************************************
  64. *
  65. * MapVGA
  66. *
  67. * map a rgb value to a VGA index
  68. *
  69. * 0000 black
  70. * 0001 dark red
  71. * 0010 dark green
  72. * 0011 mustard
  73. * 0100 dark blue
  74. * 0101 purple
  75. * 0110 dark turquoise
  76. * 1000 gray
  77. * 0111 dark gray
  78. * 1001 red
  79. * 1010 green
  80. * 1011 yellow
  81. * 1100 blue
  82. * 1101 pink (magenta)
  83. * 1110 cyan
  84. * 1111 white
  85. *
  86. *****************************************************************************/
  87. #define MapVGA(r,g,b) (((r&~3) == (g&~3) && (g&~3) == (b&~3)) ? \
  88. ((r < 64) ? 0 : (r <= 128) ? 8 : (r <= 192) ? 7 : 15) : \
  89. (((r>192) || (g>192) || (b>192)) ? \
  90. (((r>191) ? 1:0) | ((g>191) ? 2:0) | ((b>191) ? 4:0) | 8) : \
  91. (((r>64) ? 1:0) | ((g>64) ? 2:0) | ((b>64) ? 4:0))) )
  92. /*****************************************************************************
  93. *
  94. * SumRGB
  95. *
  96. *****************************************************************************/
  97. #define SumRGB(b0,b1,b2,b3) RGB(\
  98. ((int)pal.palPalEntry[b0].peRed + \
  99. (int)pal.palPalEntry[b1].peRed + \
  100. (int)pal.palPalEntry[b2].peRed + \
  101. (int)pal.palPalEntry[b3].peRed) >> 2, \
  102. \
  103. ((int)pal.palPalEntry[b0].peGreen + \
  104. (int)pal.palPalEntry[b1].peGreen + \
  105. (int)pal.palPalEntry[b2].peGreen + \
  106. (int)pal.palPalEntry[b3].peGreen) >> 2, \
  107. \
  108. ((int)pal.palPalEntry[b0].peBlue + \
  109. (int)pal.palPalEntry[b1].peBlue + \
  110. (int)pal.palPalEntry[b2].peBlue + \
  111. (int)pal.palPalEntry[b3].peBlue) >> 2)
  112. /*****************************************************************************
  113. *
  114. * RGB16
  115. *
  116. *****************************************************************************/
  117. typedef struct { BYTE b,g,r; } RGB24;
  118. #define RGB16(r,g,b) (\
  119. (((UINT)(r) >> 3) << 10) | \
  120. (((UINT)(g) >> 3) << 5) | \
  121. (((UINT)(b) >> 3) << 0) )
  122. #define rgb16(r,g,b) (\
  123. ((UINT)(r) << 10) | \
  124. ((UINT)(g) << 5) | \
  125. ((UINT)(b) << 0) )
  126. //#define RGB16R(rgb) ((((UINT)(rgb) >> 10) & 0x1F) * 255u / 31u)
  127. //#define RGB16G(rgb) ((((UINT)(rgb) >> 5) & 0x1F) * 255u / 31u)
  128. //#define RGB16B(rgb) ((((UINT)(rgb) >> 0) & 0x1F) * 255u / 31u)
  129. #define RGB16R(rgb) aw5to8[((UINT)(rgb) >> 10) & 0x1F]
  130. #define RGB16G(rgb) aw5to8[((UINT)(rgb) >> 5) & 0x1F]
  131. #define RGB16B(rgb) aw5to8[((UINT)(rgb) >> 0) & 0x1F]
  132. #define RGB16r(rgb) ((BYTE)((UINT)(rgb) >> 10) & 0x1F)
  133. #define RGB16g(rgb) ((BYTE)((UINT)(rgb) >> 5) & 0x1F)
  134. #define RGB16b(rgb) ((BYTE)((UINT)(rgb) >> 0) & 0x1F)
  135. /*****************************************************************************
  136. *
  137. * Pel() used for 24bit Crunch
  138. *
  139. *****************************************************************************/
  140. #define Pel(p,x) (BYTE)(BitCount == 1 ? Pel1(p,x) : \
  141. BitCount == 4 ? Pel4(p,x) : Pel8(p,x))
  142. #define Pel1(p,x) (BYTE)bit(((LPBYTE)(p))[(x)/8],7-((x)%8))
  143. #define Pel4(p,x) (BYTE)((x & 1) ? (((LPBYTE)(p))[(x)/2] & 15) : (((LPBYTE)(p))[(x)/2] >> 4))
  144. #define Pel8(p,x) (BYTE)(((LPBYTE)(p))[(x)])
  145. #define Pel16(p,x) (((LPWORD)(p))[(x)])
  146. #define Pel24(p,x) (((RGB24 FAR *)(p))[(x)])
  147. /*****************************************************************************
  148. *
  149. * CrunchDIB - shrink a DIB down by 2 with color averaging
  150. *
  151. * this routine works on 1,4 bpp DIBs
  152. *
  153. * for mono DIBs it is assumed they are black and white
  154. *
  155. * for 4bpp DIBs it is assumed they use the VGA colors
  156. *
  157. * this routine can't be used "in place"
  158. *
  159. *****************************************************************************/
  160. BOOL CrunchDIB(
  161. LPBITMAPINFOHEADER lpbiSrc, // BITMAPINFO of source
  162. LPVOID lpSrc, // input bits to crunch
  163. LPBITMAPINFOHEADER lpbiDst, // BITMAPINFO of dest
  164. LPVOID lpDst) // output bits to crunch
  165. {
  166. LPBYTE pbSrc;
  167. LPBYTE pbDst;
  168. LPBYTE pb;
  169. LPWORD pw;
  170. BYTE r,g,b,b0,b1,b2,b3;
  171. WORD w0,w1,w2,w3;
  172. RGB24 rgb0,rgb1,rgb2,rgb3;
  173. int WidthBytesSrc;
  174. int WidthBytesDst;
  175. UINT x;
  176. UINT y;
  177. UINT dx;
  178. UINT dy;
  179. int i;
  180. COLORREF rgb;
  181. int BitCount;
  182. UINT aw5to8[32];
  183. struct {
  184. WORD palVersion;
  185. WORD palNumEntries;
  186. PALETTEENTRY palPalEntry[256];
  187. } pal;
  188. if (lpbiSrc->biCompression != BI_RGB)
  189. return FALSE;
  190. BitCount = (int)lpbiSrc->biBitCount;
  191. if (BitCount == 16)
  192. for (i=0; i<32; i++)
  193. aw5to8[i] = (UINT)i * 255u / 31u;
  194. dx = (int)lpbiDst->biWidth;
  195. WidthBytesDst = (((UINT)lpbiDst->biBitCount * dx + 31)&~31) / 8;
  196. dy = (int)lpbiSrc->biHeight;
  197. dx = (int)lpbiSrc->biWidth;
  198. WidthBytesSrc = (((UINT)lpbiSrc->biBitCount * dx + 31)&~31) / 8;
  199. dx &= ~1;
  200. dy &= ~1;
  201. pbSrc = lpSrc;
  202. pbDst = lpDst;
  203. if (lpbiSrc->biClrUsed == 0 && lpbiSrc->biBitCount <= 8)
  204. lpbiSrc->biClrUsed = (1 << (int)lpbiSrc->biBitCount);
  205. pal.palVersion = 0x300;
  206. pal.palNumEntries = (int)lpbiSrc->biClrUsed;
  207. for (i=0; i<(int)pal.palNumEntries; i++)
  208. {
  209. pal.palPalEntry[i].peRed = ((LPRGBQUAD)(lpbiSrc+1))[i].rgbRed;
  210. pal.palPalEntry[i].peGreen = ((LPRGBQUAD)(lpbiSrc+1))[i].rgbGreen;
  211. pal.palPalEntry[i].peBlue = ((LPRGBQUAD)(lpbiSrc+1))[i].rgbBlue;
  212. pal.palPalEntry[i].peFlags = 0;
  213. }
  214. if (lpbiDst->biBitCount == 8)
  215. _fmemcpy(lpbiDst+1,lpbiSrc+1,(int)lpbiSrc->biClrUsed*sizeof(RGBQUAD));
  216. if (lpbiDst->biBitCount == 4)
  217. _fmemcpy(lpbiDst+1,VGAColors,sizeof(VGAColors));
  218. if ((int)lpbiDst->biBitCount == (int)lpbiSrc->biBitCount)
  219. {
  220. switch((int)lpbiSrc->biBitCount)
  221. {
  222. case 1:
  223. dx = dx / 8; // dx is byte count
  224. for (y=0; y<dy; y+=2)
  225. {
  226. pb = pbDst;
  227. for (x=0; x<dx; x += 2)
  228. {
  229. b0 = pbSrc[x];
  230. b1 = pbSrc[x + WidthBytesSrc];
  231. b = (BYTE)(
  232. (SumMono(bit(b0,7), bit(b0,6), bit(b1,7), bit(b1,6)) << 7) |
  233. (SumMono(bit(b0,5), bit(b0,4), bit(b1,5), bit(b1,4)) << 6) |
  234. (SumMono(bit(b0,3), bit(b0,2), bit(b1,3), bit(b1,2)) << 5) |
  235. (SumMono(bit(b0,1), bit(b0,0), bit(b1,1), bit(b1,0)) << 4));
  236. b0 = pbSrc[x + 1];
  237. b1 = pbSrc[x + 1 + WidthBytesSrc];
  238. b |=(SumMono(bit(b0,7), bit(b0,6), bit(b1,7), bit(b1,6)) << 3) |
  239. (SumMono(bit(b0,5), bit(b0,4), bit(b1,5), bit(b1,4)) << 2) |
  240. (SumMono(bit(b0,3), bit(b0,2), bit(b1,3), bit(b1,2)) << 1) |
  241. (SumMono(bit(b0,1), bit(b0,0), bit(b1,1), bit(b1,0)) << 0);
  242. *pb++ = b;
  243. }
  244. pbSrc += WidthBytesSrc*2;
  245. pbDst += WidthBytesDst;
  246. }
  247. break;
  248. case 4:
  249. dx = dx / 2; // dx is byte count
  250. for (y=0; y<dy; y+=2)
  251. {
  252. pb = pbDst;
  253. for (x=0; x<dx; x+=2)
  254. {
  255. b0 = pbSrc[x];
  256. b1 = pbSrc[x + WidthBytesSrc];
  257. rgb = SumRGB((b0 >> 4),(b0 & 0x0F),
  258. (b1 >> 4),(b1 & 0x0F));
  259. b = (BYTE)(MapVGA(GetRValue(rgb),GetGValue(rgb),GetBValue(rgb)) << 4);
  260. b0 = pbSrc[x + 1];
  261. b1 = pbSrc[x + 1 + WidthBytesSrc];
  262. rgb = SumRGB((b0 >> 4),(b0 & 0x0F),
  263. (b1 >> 4),(b1 & 0x0F));
  264. b |= MapVGA(GetRValue(rgb),GetGValue(rgb),GetBValue(rgb));
  265. *pb++ = b;
  266. }
  267. pbSrc += WidthBytesSrc*2;
  268. pbDst += WidthBytesDst;
  269. }
  270. break;
  271. #if 0
  272. case 8:
  273. {
  274. HPALETTE hpal;
  275. hpal = CreatePalette((LPLOGPALETTE)&pal);
  276. for (y=0; y<dy; y+=2)
  277. {
  278. pb = pbDst;
  279. for (x=0; x<dx; x+=2)
  280. {
  281. b0 = Pel8(pbSrc,x);
  282. b1 = Pel8(pbSrc+WidthBytesSrc, x);
  283. b2 = Pel8(pbSrc,x+1);
  284. b3 = Pel8(pbSrc+WidthBytesSrc,x+1);
  285. *pb++ = (BYTE)GetNearestPaletteIndex(hpal,
  286. SumRGB(b0,b1,b2,b3));
  287. }
  288. pbSrc += WidthBytesSrc*2;
  289. pbDst += WidthBytesDst;
  290. }
  291. DeleteObject(hpal);
  292. }
  293. break;
  294. #endif
  295. case 16:
  296. for (y=0; y<dy; y+=2)
  297. {
  298. pw = (LPWORD)pbDst;
  299. for (x=0; x<dx; x += 2)
  300. {
  301. w0 = Pel16(pbSrc,x);
  302. w1 = Pel16(pbSrc,x+1);
  303. w2 = Pel16(pbSrc+WidthBytesSrc,x);
  304. w3 = Pel16(pbSrc+WidthBytesSrc,x+1);
  305. r = ((BYTE)RGB16r(w0) + RGB16r(w1) + RGB16r(w2) + RGB16r(w3)) >> 2;
  306. g = ((BYTE)RGB16g(w0) + RGB16g(w1) + RGB16g(w2) + RGB16g(w3)) >> 2;
  307. b = ((BYTE)RGB16b(w0) + RGB16b(w1) + RGB16b(w2) + RGB16b(w3)) >> 2;
  308. *pw++ = rgb16(r,g,b);
  309. }
  310. pbSrc += WidthBytesSrc*2;
  311. pbDst += WidthBytesDst;
  312. }
  313. break;
  314. case 24:
  315. for (y=0; y<dy; y+=2)
  316. {
  317. pb = pbDst;
  318. for (x=0; x<dx; x += 2)
  319. {
  320. rgb0 = Pel24(pbSrc,x);
  321. rgb1 = Pel24(pbSrc,x+1);
  322. rgb2 = Pel24(pbSrc+WidthBytesSrc,x);
  323. rgb3 = Pel24(pbSrc+WidthBytesSrc,x+1);
  324. rgb = RGB(
  325. ((UINT)rgb0.r + rgb1.r + rgb2.r + rgb3.r)/4,
  326. ((UINT)rgb0.g + rgb1.g + rgb2.g + rgb3.g)/4,
  327. ((UINT)rgb0.b + rgb1.b + rgb2.b + rgb3.b)/4);
  328. *pb++ = GetBValue(rgb);
  329. *pb++ = GetGValue(rgb);
  330. *pb++ = GetRValue(rgb);
  331. }
  332. pbSrc += WidthBytesSrc*2;
  333. pbDst += WidthBytesDst;
  334. }
  335. break;
  336. default:
  337. return FALSE;
  338. }
  339. }
  340. else if ((int)lpbiDst->biBitCount == 24)
  341. {
  342. switch((int)lpbiSrc->biBitCount)
  343. {
  344. case 1:
  345. case 4:
  346. case 8:
  347. for (y=0; y<dy; y+=2)
  348. {
  349. pb = pbDst;
  350. for (x=0; x<dx; x += 2)
  351. {
  352. b0 = Pel(pbSrc,x);
  353. b1 = Pel(pbSrc,x+1);
  354. b2 = Pel(pbSrc+WidthBytesSrc,x);
  355. b3 = Pel(pbSrc+WidthBytesSrc,x+1);
  356. rgb = SumRGB(b0,b1,b2,b3);
  357. *pb++ = GetBValue(rgb);
  358. *pb++ = GetGValue(rgb);
  359. *pb++ = GetRValue(rgb);
  360. }
  361. pbSrc += WidthBytesSrc*2;
  362. pbDst += WidthBytesDst;
  363. }
  364. break;
  365. case 16:
  366. for (y=0; y<dy; y+=2)
  367. {
  368. pb = pbDst;
  369. for (x=0; x<dx; x += 2)
  370. {
  371. w0 = Pel16(pbSrc,x);
  372. w1 = Pel16(pbSrc,x+1);
  373. w2 = Pel16(pbSrc+WidthBytesSrc,x);
  374. w3 = Pel16(pbSrc+WidthBytesSrc,x+1);
  375. r = (RGB16R(w0) + RGB16R(w1) + RGB16R(w2) + RGB16R(w3)) / 4;
  376. g = (RGB16G(w0) + RGB16G(w1) + RGB16G(w2) + RGB16G(w3)) / 4;
  377. b = (RGB16B(w0) + RGB16B(w1) + RGB16B(w2) + RGB16B(w3)) / 4;
  378. rgb = RGB(r,g,b);
  379. *pb++ = GetBValue(rgb);
  380. *pb++ = GetGValue(rgb);
  381. *pb++ = GetRValue(rgb);
  382. }
  383. pbSrc += WidthBytesSrc*2;
  384. pbDst += WidthBytesDst;
  385. }
  386. break;
  387. default:
  388. return FALSE;
  389. }
  390. }
  391. else
  392. {
  393. return FALSE;
  394. }
  395. return TRUE;
  396. }