|
|
/****************************** Module Header ******************************\
* Module Name: cldib.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * * 09-26-95 ChrisWil Ported dib-scale code. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Constants. */ #define FX1 65536 // 1.0 in fixed point
/*
* Local Macros. */ #define BPPTOINDEX(bpp) ((UINT)(bpp) >> 3)
#define RGBQ(r,g,b) RGB(b, g, r)
#define RGBQR(rgb) GetBValue(rgb)
#define RGBQG(rgb) GetGValue(rgb)
#define RGBQB(rgb) GetRValue(rgb)
#define Pel4(p,x) (BYTE)(((x) & 1) ? (((LPBYTE)(p))[(x)/2] & 15) : (((LPBYTE)(p))[(x)/2] >> 4))
#define Pel8(p,x) (BYTE)(((LPBYTE)(p))[(x)])
#define Pel16(p,x) (((WORD UNALIGNED *)(p))[(x)])
#define Pel24(p,x) (*(DWORD UNALIGNED *)((LPBYTE)(p) + (x) * 3))
/*
* Function Typedefs. */ typedef VOID (*SCALEPROC)(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); typedef VOID (*INITPROC)(LPBITMAPINFOHEADER);
/*
* Local Routines. */ BOOL ScaleDIB(LPBITMAPINFOHEADER, LPVOID, LPBITMAPINFOHEADER, LPVOID); VOID InitDst8(LPBITMAPINFOHEADER); VOID Scale48(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); VOID Scale88(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); VOID Scale424(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); VOID Scale824(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); VOID Scale2424(LPDWORD, LPBYTE, long, int, int, int, int, LPBYTE, long, int, int); BYTE Map8(COLORREF); COLORREF MixRGBI(LPDWORD, BYTE, BYTE,BYTE, BYTE, int, int); COLORREF MixRGB(DWORD, DWORD, DWORD, DWORD, int, int);
/*
* Globals needed for color-mapping of resources. */ SCALEPROC ScaleProc[4][4] = { NULL, Scale48, NULL, Scale424, NULL, Scale88, NULL, Scale824, NULL, NULL , NULL, NULL, NULL, NULL , NULL, Scale2424 };
INITPROC InitDst[] = { NULL, InitDst8, NULL, NULL };
BYTE rmap[256], gmap[256], bmap[256];
/***************************************************************************\
* SmartStretchDIBits * * calls GDI StretchDIBits, unless the stretch is 2:1 and the source * is 4bpp, then is does it itself in a nice way. * * this optimization should just be put into GDI. * * can we change the passed bits? I assume we cant, could avoid a alloc * if so. * \***************************************************************************/
int SmartStretchDIBits( HDC hdc, int xD, int yD, int dxD, int dyD, int xS, int yS, int dxS, int dyS, LPVOID lpBits, LPBITMAPINFO lpbi, UINT wUsage, DWORD rop) { LPBYTE lpBitsNew; UINT bpp; RGBQUAD rgb; LPBITMAPINFOHEADER lpbiNew = NULL;
int i;
/*
* thunk to USER32 */ UserAssert(rop == SRCCOPY); UserAssert(wUsage == DIB_RGB_COLORS); UserAssert(xS == 0 && yS == 0);
if ((GetDIBColorTable(hdc, 0, 1, &rgb) != 1) && (dxD != dxS || dyD != dyS) && // 1:1 stretch just call GDI
(dxD >= dxS/2) && (dyD >= dyS/2) && // less than 1:2 shrink call GDI
(lpbi->bmiHeader.biCompression == 0) && // must be un-compressed
(lpbi->bmiHeader.biBitCount == 4 || // input must be 4,8,24
lpbi->bmiHeader.biBitCount == 8 || lpbi->bmiHeader.biBitCount == 24)) {
bpp = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
bpp = (bpp > 8 ? 24 : 8);
lpbiNew = (LPBITMAPINFOHEADER)UserLocalAlloc(0, sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD)) + (UINT)((((dxD * bpp) / 8) + 3) & ~3) * (UINT)dyD);
if (lpbiNew) {
*lpbiNew = lpbi->bmiHeader; lpbiNew->biWidth = dxD; lpbiNew->biHeight = dyD; lpbiNew->biBitCount = (WORD)bpp; lpBitsNew = (LPBYTE)lpbiNew + sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD));
if (ScaleDIB((LPBITMAPINFOHEADER)lpbi, (LPVOID)lpBits, lpbiNew, lpBitsNew)) {
lpbi = (LPBITMAPINFO)lpbiNew; lpBits = lpBitsNew; dxS = dxD; dyS = dyD; } } }
i = StretchDIBits(hdc, xD, yD, dxD, dyD, xS, yS, dxS, dyS, lpBits, lpbi, wUsage, rop);
if (lpbiNew) UserLocalFree(lpbiNew);
return i; }
/***************************************************************************\
* ScaleDIB * * Parameters * ---------- * lpbiSrc - BITMAPINFO of source. * lpSrc - Input bits to crunch. * lpbiDst - BITMAPINFO of destination. * lpDst - Output bits to crunch. * * \***************************************************************************/
BOOL ScaleDIB( LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst) { LPBYTE pbSrc; LPBYTE pbDst; LPDWORD pal; int dxSrc; int dySrc; int dxDst; int dyDst; int iSrc; int iDst; int x0; int y0; int sdx; int sdy; LONG WidthBytesSrc; LONG WidthBytesDst;
if ((lpbiSrc->biCompression != BI_RGB) || (lpbiDst->biCompression != BI_RGB)) { return FALSE; }
iSrc = BPPTOINDEX(lpbiSrc->biBitCount); iDst = BPPTOINDEX(lpbiDst->biBitCount);
if (ScaleProc[iSrc][iDst] == NULL) return FALSE;
dxSrc = (int)lpbiSrc->biWidth; dySrc = (int)lpbiSrc->biHeight;
dxDst = (int)lpbiDst->biWidth; dyDst = (int)lpbiDst->biHeight;
WidthBytesDst = BitmapWidth(lpbiDst->biWidth, lpbiDst->biBitCount); WidthBytesSrc = BitmapWidth(lpbiSrc->biWidth, lpbiSrc->biBitCount);
lpbiDst->biSizeImage = (WidthBytesDst * dyDst);
pbSrc = (LPBYTE)lpSrc; pbDst = (LPBYTE)lpDst;
pal = (LPDWORD)(lpbiSrc + 1);
if (InitDst[iDst]) InitDst[iDst](lpbiDst);
if ((dxSrc == (dxDst * 2)) && (dySrc == (dyDst * 2))) {
sdx = FX1 * 2; sdy = FX1 * 2; y0 = FX1 / 2; x0 = FX1 / 2;
} else {
sdx = (dxSrc - 1) * FX1 / (dxDst - 1); sdy = (dySrc - 1) * FX1 / (dyDst - 1); y0 = 0; x0 = 0; }
/*
* Make sure we don't croak on a bad bitmap since this can hose winlogon * if it's the desktop wallpaper. */ try { ScaleProc[iSrc][iDst](pal, pbSrc, WidthBytesSrc, x0, y0, sdx, sdy, pbDst, WidthBytesDst, dxDst, dyDst); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { return FALSE; }
return TRUE; }
/***************************************************************************\
* Scale48 * * \***************************************************************************/
VOID Scale48( LPDWORD pal, LPBYTE pbSrc, LONG WidthBytesSrc, int x0, int y0, int sdx, int sdy, LPBYTE pbDst, LONG WidthBytesDst, int dxDst, int dyDst) { BYTE b0; BYTE b1; BYTE b2; BYTE b3; LPBYTE pb; int x; int y; UINT sx; UINT sy;
for (sy=y0, y=0; y < dyDst; y++, sy+=sdy) {
pb = pbSrc + (WidthBytesSrc * (sy / FX1));
for (sx=x0, x=0; x < dxDst; x++, sx+=sdx) {
b0 = Pel4(pb, (sx / FX1)); b1 = Pel4(pb, (sx / FX1) + 1); b2 = Pel4(pb + WidthBytesSrc, (sx / FX1)); b3 = Pel4(pb + WidthBytesSrc, (sx / FX1) + 1);
pbDst[x] = Map8(MixRGBI(pal, b0, b1, b2, b3, sx % FX1, sy % FX1)); }
pbDst += WidthBytesDst; } }
/***************************************************************************\
* Scale88 * * \***************************************************************************/
VOID Scale88( LPDWORD pal, LPBYTE pbSrc, LONG WidthBytesSrc, int x0, int y0, int sdx, int sdy, LPBYTE pbDst, LONG WidthBytesDst, int dxDst, int dyDst) { BYTE b0; BYTE b1; BYTE b2; BYTE b3; LPBYTE pb; int x; int y; UINT sx; UINT sy;
for (sy=y0, y=0; y < dyDst; y++, sy+=sdy) {
pb = pbSrc + (WidthBytesSrc * (sy / FX1));
for (sx=x0, x=0; x < dxDst; x++, sx+=sdx) {
b0 = Pel8(pb, (sx / FX1)); b1 = Pel8(pb, (sx / FX1) + 1); b2 = Pel8(pb + WidthBytesSrc, (sx / FX1)); b3 = Pel8(pb + WidthBytesSrc, (sx / FX1) + 1);
pbDst[x] = Map8(MixRGBI(pal, b0, b1, b2, b3, sx % FX1, sy % FX1)); }
pbDst += WidthBytesDst; } }
/***************************************************************************\
* Scale424 * * \***************************************************************************/
VOID Scale424( LPDWORD pal, LPBYTE pbSrc, LONG WidthBytesSrc, int x0, int y0, int sdx, int sdy, LPBYTE pbDst, LONG WidthBytesDst, int dxDst, int dyDst) { BYTE b0; BYTE b1; BYTE b2; BYTE b3; LPBYTE pb; int x; int y; UINT sx; UINT sy; COLORREF rgb;
for (sy=y0, y=0; y < dyDst; y++, sy+=sdy) {
pb = pbSrc + (WidthBytesSrc * (sy / FX1));
for (sx=x0, x=0; x < dxDst; x++, sx+=sdx) {
b0 = Pel4(pb, (sx / FX1)); b1 = Pel4(pb, (sx / FX1) + 1); b2 = Pel4(pb + WidthBytesSrc, (sx / FX1)); b3 = Pel4(pb + WidthBytesSrc, (sx / FX1) + 1);
rgb = MixRGBI(pal, b0, b1, b2, b3, sx % FX1, sy % FX1);
*pbDst++ = GetBValue(rgb); *pbDst++ = GetGValue(rgb); *pbDst++ = GetRValue(rgb); }
pbDst += (WidthBytesDst - (dxDst * 3)); } }
/***************************************************************************\
* Scale824 * * \***************************************************************************/
VOID Scale824( LPDWORD pal, LPBYTE pbSrc, LONG WidthBytesSrc, int x0, int y0, int sdx, int sdy, LPBYTE pbDst, LONG WidthBytesDst, int dxDst, int dyDst) { BYTE b0; BYTE b1; BYTE b2; BYTE b3; LPBYTE pb; int x; int y; UINT sx; UINT sy; COLORREF rgb;
for (sy=y0, y=0; y < dyDst; y++, sy+=sdy) {
pb = pbSrc + (WidthBytesSrc * (sy / FX1));
for (sx=x0, x=0; x < dxDst; x++, sx+=sdx) {
b0 = Pel8(pb, (sx / FX1)); b1 = Pel8(pb, (sx / FX1) + 1); b2 = Pel8(pb + WidthBytesSrc, (sx / FX1)); b3 = Pel8(pb + WidthBytesSrc, (sx / FX1) + 1);
rgb = MixRGBI(pal, b0, b1, b2, b3, sx % FX1, sy % FX1);
*pbDst++ = GetBValue(rgb); *pbDst++ = GetGValue(rgb); *pbDst++ = GetRValue(rgb); }
pbDst += (WidthBytesDst - (dxDst * 3)); } }
/***************************************************************************\
* Scale2424 * * \***************************************************************************/
VOID Scale2424( LPDWORD pal, LPBYTE pbSrc, LONG WidthBytesSrc, int x0, int y0, int sdx, int sdy, LPBYTE pbDst, LONG WidthBytesDst, int dxDst, int dyDst) { DWORD bgr0; DWORD bgr1; DWORD bgr2; DWORD bgr3; LPBYTE pb; int x; int y; UINT sx; UINT sy; COLORREF rgb;
UNREFERENCED_PARAMETER(pal);
for (sy=y0, y=0; y < dyDst; y++, sy+=sdy) {
pb = pbSrc + (WidthBytesSrc * (sy / FX1));
for (sx=x0, x=0; x < dxDst; x++, sx+=sdx) {
bgr0 = Pel24(pb, (sx / FX1)); bgr1 = Pel24(pb, (sx / FX1) + 1); bgr2 = Pel24(pb + WidthBytesSrc, (sx / FX1)); bgr3 = Pel24(pb + WidthBytesSrc, (sx / FX1) + 1);
rgb = MixRGB(bgr0, bgr1, bgr2, bgr3, sx % FX1, sy % FX1);
*pbDst++ = GetBValue(rgb); *pbDst++ = GetGValue(rgb); *pbDst++ = GetRValue(rgb); }
pbDst += (WidthBytesDst - (dxDst * 3)); } }
/***************************************************************************\
* MixRGB * * r0 x r1 * y * * r2 r3 * * Note: inputs are RGBQUADs, output is a COLORREF. * \***************************************************************************/
COLORREF MixRGB( DWORD r0, DWORD r1, DWORD r2, DWORD r3, int x, int y) { int r; int g; int b;
if (x == 0 && y == 0) {
r = RGBQR(r0); g = RGBQG(r0); b = RGBQB(r0);
} else if (x == 0) {
r = ((FX1-y) * RGBQR(r0) + y * RGBQR(r2))/FX1; g = ((FX1-y) * RGBQG(r0) + y * RGBQG(r2))/FX1; b = ((FX1-y) * RGBQB(r0) + y * RGBQB(r2))/FX1; } else if (y == 0) { r = ((FX1-x) * RGBQR(r0) + x * RGBQR(r1))/FX1; g = ((FX1-x) * RGBQG(r0) + x * RGBQG(r1))/FX1; b = ((FX1-x) * RGBQB(r0) + x * RGBQB(r1))/FX1; } else if (x == FX1/2 && y == FX1/2) { r = (RGBQR(r0) + RGBQR(r1) + RGBQR(r2) + RGBQR(r3))/4; g = (RGBQG(r0) + RGBQG(r1) + RGBQG(r2) + RGBQG(r3))/4; b = (RGBQB(r0) + RGBQB(r1) + RGBQB(r2) + RGBQB(r3))/4; } else { r =((ULONG)RGBQR(r0) * (FX1-x) / FX1 * (FX1-y) + (ULONG)RGBQR(r1) * x / FX1 * (FX1-y) + (ULONG)RGBQR(r2) * (FX1-x) / FX1 * y + (ULONG)RGBQR(r3) * x / FX1 * y )/FX1;
g =((ULONG)RGBQG(r0) * (FX1-x) / FX1 * (FX1-y) + (ULONG)RGBQG(r1) * x / FX1 * (FX1-y) + (ULONG)RGBQG(r2) * (FX1-x) / FX1 * y + (ULONG)RGBQG(r3) * x / FX1 * y )/FX1;
b =((ULONG)RGBQB(r0) * (FX1-x) / FX1 * (FX1-y) + (ULONG)RGBQB(r1) * x / FX1 * (FX1-y) + (ULONG)RGBQB(r2) * (FX1-x) / FX1 * y + (ULONG)RGBQB(r3) * x / FX1 * y )/FX1; }
return RGB(r,g,b); }
/***************************************************************************\
* MixRGBI * * \***************************************************************************/
_inline COLORREF MixRGBI( LPDWORD pal, BYTE b0, BYTE b1, BYTE b2, BYTE b3, int x, int y) { if (((b0 == b1) && (b1 == b2) && (b2 == b3)) || ((x == 0) && (y == 0))) return RGBX(pal[b0]); else return MixRGB(pal[b0], pal[b1], pal[b2], pal[b3], x, y); }
/***************************************************************************\
* InitDst8 * * \***************************************************************************/
_inline VOID InitDst8( LPBITMAPINFOHEADER lpbi) { int r; int g; int b; LPDWORD pdw;
pdw = (LPDWORD)(lpbi + 1); lpbi->biClrUsed = 6*6*6;
for (r=0; r < 6; r++) {
for (g=0; g < 6; g++) {
for (b=0; b < 6; b++) { *pdw++ = RGBQ((r * 255) / 5, (g * 255) / 5, (b * 255) / 5); } } }
for (b=0; b < 256; b++) { bmap[b] = (b * 5 + 128) / 255; gmap[b] = 6 * bmap[b]; rmap[b] = 36 * bmap[b]; } }
/***************************************************************************\
* Map8 * * \***************************************************************************/
_inline BYTE Map8( COLORREF rgb) { return rmap[GetRValue(rgb)] + gmap[GetGValue(rgb)] + bmap[GetBValue(rgb)]; }
|