windows-nt/Source/XPSP1/NT/multimedia/media/avi/drawdib/dither.c

357 lines
10 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <windows.h>
#include <windowsx.h>
#include "drawdibi.h"
#include "dither.h"
//#define GRAY_SCALE
extern BOOL gf286;
extern UINT gwRasterCaps;
void FAR PASCAL Map16to24(LPBITMAPINFOHEADER,LPVOID,int,int,int,int,LPBITMAPINFOHEADER,LPVOID,int,int,LPVOID);
extern LPVOID glpDitherTable;
//////////////////////////////////////////////////////////////////////////////
//
// DitherInit()
//
//////////////////////////////////////////////////////////////////////////////
LPVOID VFWAPI
DitherInit(LPBITMAPINFOHEADER lpbiIn,
LPBITMAPINFOHEADER lpbiOut,
DITHERPROC FAR * lpDitherProc,
LPVOID lpDitherTable)
{
switch ((int)lpbiOut->biBitCount)
{
case 8:
if ((int)lpbiIn->biBitCount == 8 && (gwRasterCaps & RC_PALETTE))
return Dither8Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
if ((int)lpbiIn->biBitCount == 8 && !(gwRasterCaps & RC_PALETTE))
return DitherDeviceInit(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
if ((int)lpbiIn->biBitCount == 16)
return Dither16Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
if ((int)lpbiIn->biBitCount == 24)
return Dither24Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
if ((int)lpbiIn->biBitCount == 32)
return Dither32Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
return (LPVOID)-1;
case 24:
#ifndef _WIN32
if (!gf286)
#endif
{
if (lpbiIn->biBitCount == 16) {
*lpDitherProc = Map16to24;
return NULL;
} else if (lpbiIn->biBitCount == 32) {
*lpDitherProc = Map32to24;
return NULL;
}
}
return (LPVOID)-1;
default:
return (LPVOID)-1;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// DitherTerm()
//
//////////////////////////////////////////////////////////////////////////////
void VFWAPI
DitherTerm(LPVOID lpDitherTable)
{
if (lpDitherTable == glpDitherTable)
Dither16Term(lpDitherTable);
else
Dither8Term(lpDitherTable);
}
//////////////////////////////////////////////////////////////////////////////
//
// DitherDeviceInit() - dither to the colors of the display driver
//
//////////////////////////////////////////////////////////////////////////////
LPVOID FAR PASCAL DitherDeviceInit(LPBITMAPINFOHEADER lpbi, LPBITMAPINFOHEADER lpbiOut, DITHERPROC FAR *lpDitherProc, LPVOID lpDitherTable)
{
HBRUSH hbr;
HDC hdcMem;
HDC hdc;
HBITMAP hbm;
HBITMAP hbmT;
int i;
int nColors;
LPRGBQUAD prgb;
BITMAPINFOHEADER biSave = *lpbiOut;
//
// we dont need to re-init the dither table, unless it is not ours then
// we should free it.
//
if (lpDitherTable == glpDitherTable)
{
DitherTerm(lpDitherTable);
lpDitherTable = NULL;
}
if (lpDitherTable == NULL)
{
lpDitherTable = GlobalAllocPtr(GHND, 256*8*8);
}
if (lpDitherTable == NULL)
return (LPVOID)-1;
hdc = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdc);
hbm = CreateCompatibleBitmap(hdc, 256*8, 8);
hbmT = SelectObject(hdcMem, hbm);
if ((nColors = (int)lpbi->biClrUsed) == 0)
nColors = 1 << (int)lpbi->biBitCount;
prgb = (LPRGBQUAD)(lpbi+1);
for (i=0; i<nColors; i++)
{
hbr = CreateSolidBrush(RGB(prgb[i].rgbRed,prgb[i].rgbGreen,prgb[i].rgbBlue));
hbr = SelectObject(hdcMem, hbr);
PatBlt(hdcMem, i*8, 0, 8, 8, PATCOPY);
hbr = SelectObject(hdcMem, hbr);
DeleteObject(hbr);
}
#ifdef XDEBUG
for (i=0; i<16; i++)
BitBlt(hdc,0,i*8,16*8,8,hdcMem,i*(16*8),0,SRCCOPY);
#endif
SelectObject(hdcMem, hbmT);
DeleteDC(hdcMem);
lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
lpbiOut->biPlanes = 1;
lpbiOut->biBitCount = 8;
lpbiOut->biWidth = 256*8;
lpbiOut->biHeight = 8;
lpbiOut->biCompression = BI_RGB;
lpbiOut->biSizeImage = 256*8*8;
lpbiOut->biXPelsPerMeter = 0;
lpbiOut->biYPelsPerMeter = 0;
lpbiOut->biClrUsed = 0;
lpbiOut->biClrImportant = 0;
GetDIBits(hdc, hbm, 0, 8, lpDitherTable, (LPBITMAPINFO)lpbiOut, DIB_RGB_COLORS);
i = (int)lpbiOut->biClrUsed;
*lpbiOut = biSave;
lpbiOut->biClrUsed = i;
DeleteObject(hbm);
ReleaseDC(NULL, hdc);
*lpDitherProc = Dither8;
return (LPVOID)lpDitherTable;
}
//////////////////////////////////////////////////////////////////////////////
//
// DitherTerm()
//
//////////////////////////////////////////////////////////////////////////////
void FAR PASCAL Dither8Term(LPVOID lpDitherTable)
{
if (lpDitherTable)
GlobalFreePtr(lpDitherTable);
}
#ifdef _WIN32
//
// call this to actually do the dither.
//
void FAR PASCAL Dither8(
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
LPVOID lpDst, // --> to destination bits
int DstX, // Destination origin - x coordinate
int DstY, // Destination origin - y coordinate
int DstXE, // x extent of the BLT
int DstYE, // y extent of the BLT
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
LPVOID lpSrc, // --> to source bits
int SrcX, // Source origin - x coordinate
int SrcY, // Source origin - y coordinate
LPVOID lpDitherTable) // dither table.
{
int x,y;
UINT wWidthSrc;
UINT wWidthDst;
BYTE _huge *pbS;
BYTE _huge *pbD;
DWORD dw;
if (biDst->biBitCount != 8 || biSrc->biBitCount != 8)
return;
// tomor -- A little help! seems initialization is not done yet.
if(!lpDitherTable)
return;
wWidthSrc = ((UINT)biSrc->biWidth+3)&~3;
wWidthDst = ((UINT)biDst->biWidth+3)&~3;
pbD = (BYTE _huge *)lpDst + DstX + DstY * wWidthDst;
pbS = (BYTE _huge *)lpSrc + SrcX + SrcY * wWidthSrc;
wWidthSrc -= DstXE;
wWidthDst -= DstXE;
#define DODITH8(px, x, y) ((LPBYTE)lpDitherTable)[((y) & 7) * 256 * 8 + (px) * 8 + (x & 7)]
for (y=0; y<DstYE; y++) {
/* write two DWORDs (one dither cell horizontally) at once */
for (x=0; x <= (DstXE - 8); x += 8) {
dw = DODITH8(*pbS++, 0, y);
dw |= (DODITH8(*pbS++, 1, y) << 8);
dw |= (DODITH8(*pbS++, 2, y) << 16);
dw |= (DODITH8(*pbS++, 3, y) << 24);
* ( (DWORD _huge UNALIGNED *) pbD)++ = dw;
dw = DODITH8(*pbS++, 4, y);
dw |= (DODITH8(*pbS++, 5, y) << 8);
dw |= (DODITH8(*pbS++, 6, y) << 16);
dw |= (DODITH8(*pbS++, 7, y) << 24);
* ( (DWORD _huge UNALIGNED *) pbD)++ = dw;
}
/* clean up remainder (less than 8 bytes per row) */
for ( ; x < DstXE; x++) {
*pbD++ = DODITH8(*pbS++, x, y);
}
pbS += wWidthSrc;
pbD += wWidthDst;
}
#undef DODITH8
}
/*
* C version of 16->24 mapping (in asm for win16)
*/
extern void FAR PASCAL Map16to24(
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
LPVOID lpDst, // --> to destination bits
int DstX, // Destination origin - x coordinate
int DstY, // Destination origin - y coordinate
int DstXE, // x extent of the BLT
int DstYE, // y extent of the BLT
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
LPVOID lpSrc, // --> to source bits
int SrcX, // Source origin - x coordinate
int SrcY, // Source origin - y coordinate
LPVOID lpDitherTable) // dither table.
{
int x,y;
UINT wWidthSrc;
UINT wWidthDst;
BYTE _huge *pbS;
BYTE _huge *pbD;
WORD wRGB;
if (biDst->biBitCount != 24 || biSrc->biBitCount != 16)
return;
/* width of one row is nr pixels * size of pixel rounded to 4-bytes */
wWidthSrc = ((UINT) (biSrc->biWidth * 2) +3)&~3;
wWidthDst = ((UINT) (biDst->biWidth * 3) +3)&~3;
/* advance to start of source, dest rect within DIB */
pbD = (BYTE _huge *)lpDst + (DstX * 3) + DstY * wWidthDst;
pbS = (BYTE _huge *)lpSrc + (SrcX * 2) + SrcY * wWidthSrc;
/* amount to advance pointer to next line from end of source, dest rect */
wWidthSrc -= (DstXE * 2);
wWidthDst -= (DstXE * 3);
for (y=0; y<DstYE; y++) {
for (x=0; x<DstXE; x++) {
wRGB = *((LPWORD)pbS)++;
*pbD++ = (wRGB << 3) & 0xf8;
*pbD++ = (wRGB >> 2) & 0xf8;
*pbD++ = (wRGB >> 7) & 0xf8;
}
pbS += wWidthSrc;
pbD += wWidthDst;
}
}
void FAR PASCAL Map32to24(
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
LPVOID lpDst, // --> to destination bits
int DstX, // Destination origin - x coordinate
int DstY, // Destination origin - y coordinate
int DstXE, // x extent of the BLT
int DstYE, // y extent of the BLT
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
LPVOID lpSrc, // --> to source bits
int SrcX, // Source origin - x coordinate
int SrcY, // Source origin - y coordinate
LPVOID lpDitherTable) // dither table.
{
int x,y;
UINT wWidthSrc;
UINT wWidthDst;
BYTE _huge *pbS;
BYTE _huge *pbD;
if (biDst->biBitCount != 24 || biSrc->biBitCount != 32)
return;
/* width of one row is nr pixels * size of pixel rounded to 4-bytes */
//wWidthSrc = ((UINT) (biSrc->biWidth * 4) +3)&~3;
// Multiplying by 4 ensures it is rounded to 4 bytes...
wWidthSrc = (UINT) (biSrc->biWidth * 4);
wWidthDst = ((UINT) (biDst->biWidth * 3) +3)&~3;
/* advance to start of source, dest rect within DIB */
pbD = (BYTE _huge *)lpDst + (DstX * 3) + DstY * wWidthDst;
pbS = (BYTE _huge *)lpSrc + (SrcX * 4) + SrcY * wWidthSrc;
/* amount to advance pointer to next line from end of source, dest rect */
wWidthSrc -= (DstXE * 4);
wWidthDst -= (DstXE * 3);
for (y=0; y<DstYE; y++) {
for (x=0; x<DstXE; x++) {
*pbD++ = *pbS++;
*pbD++ = *pbS++;
*pbD++ = *pbS++;
pbS++;
}
pbS += wWidthSrc;
pbD += wWidthDst;
}
}
#endif