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.
 
 
 
 
 
 

1283 lines
39 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Eric W. Sink [email protected]
*/
#include "all.h"
extern HPALETTE hPalGuitar;
//
// Load a device-independant bitmap resource, and map it into our palette
//
HBITMAP
LoadResourceDIBitmap(
HINSTANCE hInstance,
LPSTR lpID // Resource ID
)
{
HRSRC hRsrc;
HGLOBAL hGlobal;
HBITMAP hBitmapFinal = NULL;
LPBITMAPINFOHEADER lpbi;
HDC hDC;
int iNumColors;
if (hRsrc = FindResource(hInstance, lpID, RT_BITMAP))
{
hGlobal = LoadResource(hInstance, hRsrc);
lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal);
if (lpbi->biBitCount <= 8)
{
iNumColors = (1 << lpbi->biBitCount);
}
else
{
iNumColors = 0; // No palette needed for 24 Bit
}
hDC = GetDC(NULL);
GTR_RealizePalette(hDC);
hBitmapFinal = CreateDIBitmap(hDC,
(LPBITMAPINFOHEADER)lpbi,
(LONG)CBM_INIT,
(LPSTR)lpbi + lpbi->biSize + iNumColors * sizeof(RGBQUAD),
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS
);
ReleaseDC(NULL, hDC);
UnlockResource(hGlobal);
FreeResource(hGlobal);
}
return hBitmapFinal;
}
/*
This routine should only be used when drawing to an 8 bit palette screen.
Also, it is only used when the pixel data is already prematched to the global
palette. Currently, this happens for both GIF and JPEG images, since they
are dithered into the global palette as they are read. It also handles the
case of a B/W image (ie, XBMs). B/W images are created with their pixels set
to the foreground and background colors of the screen, in the global palette.
*/
PBITMAPINFO BIT_Make_DIB_PAL_Header_Prematched(int xsize, int ysize, CONST BYTE * pdata, unsigned int flags)
{
int i;
PBITMAPINFO pbmi;
WORD *pw;
if (flags & IMG_BW)
{
//pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 2 * sizeof(DWORD));
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
if (xsize % 16)
{
xsize += (16 - (xsize % 16));
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 2;
pbmi->bmiHeader.biClrImportant = 0;
pw = (WORD *) pbmi->bmiColors;
pw[0] = BACKGROUND_COLOR_INDEX;
pw[1] = FOREGROUND_COLOR_INDEX;
}
else
{
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 256 * sizeof(WORD));
if (!pbmi)
{
return NULL;
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 256;
pbmi->bmiHeader.biClrImportant = 0;
pw = (WORD *) pbmi->bmiColors;
for (i = 0; i < 256; i++)
{
if (i < (NUM_MAIN_PALETTE_COLORS + NUM_EXTRA_PALETTE_COLORS))
{
pw[i] = i;
}
else
{
pw[i] = 0;
}
}
}
return pbmi;
}
/*
This routine is used when drawing to printers. It always creates DIBs in
DIB_RGB_COLORS format, and it will accept arbitrary 8 bit data with
an arbitrary palette. Transparent colors are handled using white.
The foreground color for B/W images is black.
*/
PBITMAPINFO BIT_Make_DIB_RGB_Header_Printer(int xsize, int ysize, CONST BYTE * pdata, HPALETTE hPalette, int transparent, unsigned int flags)
{
PALETTEENTRY pe[256];
int i;
PBITMAPINFO pbmi;
if (flags & IMG_BW)
{
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
if (xsize % 16)
{
xsize += (16 - (xsize % 16));
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 2;
pbmi->bmiHeader.biClrImportant = 0;
/*
When printing, we force XBMs to be black and white
*/
pbmi->bmiColors[0].rgbRed = 255;
pbmi->bmiColors[0].rgbGreen = 255;
pbmi->bmiColors[0].rgbBlue = 255;
pbmi->bmiColors[0].rgbReserved = 0;
pbmi->bmiColors[1].rgbRed = 0;
pbmi->bmiColors[1].rgbGreen = 0;
pbmi->bmiColors[1].rgbBlue = 0;
pbmi->bmiColors[1].rgbReserved = 0;
}
else
{
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 256;
pbmi->bmiHeader.biClrImportant = 0;
GetPaletteEntries(hPalette, 0, 256, pe);
for (i = 0; i < 256; i++)
{
pbmi->bmiColors[i].rgbRed = pe[i].peRed;
pbmi->bmiColors[i].rgbGreen = pe[i].peGreen;
pbmi->bmiColors[i].rgbBlue = pe[i].peBlue;
pbmi->bmiColors[i].rgbReserved = 0;
}
if (transparent != -1)
{
/*
Paper is white
*/
pbmi->bmiColors[transparent].rgbRed = 255;
pbmi->bmiColors[transparent].rgbGreen = 255;
pbmi->bmiColors[transparent].rgbBlue = 255;
}
}
return pbmi;
}
/*
This routine is used when drawing to the nonpalette screens. It always creates
DIBs in DIB_RGB_COLORS format. For B/W images, a 2-entry palette is constructed
using the foreground and background colors for the window. For color images,
if there is a transparent color, it is modified in the palette to be the
background color for the window.
*/
PBITMAPINFO BIT_Make_DIB_RGB_Header_Screen(int xsize, int ysize, CONST BYTE * pdata, HPALETTE hPalette, int transparent, unsigned int flags)
{
PALETTEENTRY pe[256];
int i;
PBITMAPINFO pbmi;
if (flags & IMG_BW)
{
COLORREF color;
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
if (xsize % 16)
{
xsize += (16 - (xsize % 16));
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 2;
pbmi->bmiHeader.biClrImportant = 0;
color = PREF_GetBackgroundColor();
pbmi->bmiColors[0].rgbRed = GetRValue(color);
pbmi->bmiColors[0].rgbGreen = GetGValue(color);
pbmi->bmiColors[0].rgbBlue = GetBValue(color);
pbmi->bmiColors[0].rgbReserved = 0;
color = PREF_GetForegroundColor();
pbmi->bmiColors[1].rgbRed = GetRValue(color);
pbmi->bmiColors[1].rgbGreen = GetGValue(color);
pbmi->bmiColors[1].rgbBlue = GetBValue(color);
pbmi->bmiColors[1].rgbReserved = 0;
}
else
{
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 256;
pbmi->bmiHeader.biClrImportant = 0;
GetPaletteEntries(hPalette, 0, 256, pe);
for (i = 0; i < 256; i++)
{
pbmi->bmiColors[i].rgbRed = pe[i].peRed;
pbmi->bmiColors[i].rgbGreen = pe[i].peGreen;
pbmi->bmiColors[i].rgbBlue = pe[i].peBlue;
pbmi->bmiColors[i].rgbReserved = 0;
}
if (transparent != -1)
{
COLORREF color;
color = PREF_GetBackgroundColor();
pbmi->bmiColors[transparent].rgbRed = GetRValue(color);
pbmi->bmiColors[transparent].rgbGreen = GetGValue(color);
pbmi->bmiColors[transparent].rgbBlue = GetBValue(color);
}
}
return pbmi;
}
DWORD vga_colors[16]={RGB( 0, 0, 0), //Black
RGB(128, 0, 0), //Dark red
RGB( 0, 128, 0), //Dark green
RGB(128, 128, 0), //Dark yellow
RGB( 0, 0, 128), //Dark blue
RGB(128, 0, 128), //Dark purple
RGB( 0, 128, 128), //Dark aqua
RGB(128, 128, 128), //Dark grey
RGB(192, 192, 192), //Light grey
RGB(255, 0, 0), //Light red
RGB( 0, 255, 0), //Light green
RGB(255, 255, 0), //Light yellow
RGB( 0, 0, 255), //Light blue
RGB(255, 0, 255), //Light purple
RGB( 0, 255, 255), //Light aqua
RGB(255, 255, 255), //White
};
/*
This routine is used when drawing to the 16 color screens. It always creates
DIBs in DIB_RGB_COLORS format. It is used when an image happens to be
prematched to the VGA palette at load time, such as a JPEG which is
dithered using those 16 colors.
*/
PBITMAPINFO BIT_Make_DIB_RGB_Header_VGA(int xsize, int ysize, CONST BYTE * pdata)
{
int i;
PBITMAPINFO pbmi;
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD));
if (!pbmi)
{
return NULL;
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 16;
pbmi->bmiHeader.biClrImportant = 0;
for (i = 0; i < 16; i++)
{
pbmi->bmiColors[i].rgbRed = GetRValue(vga_colors[i]);
pbmi->bmiColors[i].rgbGreen = GetGValue(vga_colors[i]);
pbmi->bmiColors[i].rgbBlue = GetBValue(vga_colors[i]);
pbmi->bmiColors[i].rgbReserved = 0;
}
return pbmi;
}
/*
This routine is used when drawing to truecolor screens. It always creates
DIBs in 24 bit format. It is used for truecolor image formats like
JPEG.
*/
PBITMAPINFO BIT_Make_DIB_RGB_Header_24BIT(int xsize, int ysize, CONST BYTE * pdata)
{
PBITMAPINFO pbmi;
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER));
if (!pbmi)
{
return NULL;
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = xsize;
pbmi->bmiHeader.biHeight = ysize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 24;
pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
return pbmi;
}
/*
This function is only used for printing. We take the DIB as stored in the
ImageInfo structure and adapt it to be in DIB_RGB_COLORS format, suitable
for printing.
*/
int Printer_StretchDIBits(HDC hdc, int XDest, int YDest, int nDestWidth, int nDestHeight,
int XSrc, int YSrc, int nSrcWidth, int nSrcHeight,
struct ImageInfo *img)
{
PBITMAPINFO pbmi;
int err;
extern HPALETTE hPalGuitar;
if (wg.eColorMode == 8 && (img->flags & IMG_PREMATCHED))
{
/*
On 8 bit screens, color images are stored in DIB_PAL_COLORS
format, so we need to construct a DIB_RGB_COLORS format DIB
using the global palette.
*/
pbmi = BIT_Make_DIB_RGB_Header_Printer(img->width, img->height,
img->data, hPalGuitar, BACKGROUND_COLOR_INDEX, img->flags);
}
else
{
if ((wg.eColorMode == 4) && (img->flags & IMG_JPEG))
{
/*
On 4-bit screens, we use the IJG dithering code to dither
directly to a VGA palette
*/
pbmi = BIT_Make_DIB_RGB_Header_VGA(img->width, img->height, img->data);
}
else if ((wg.eColorMode == 16) && (img->flags & IMG_JPEG))
{
/*
On 16-bit screens, we just send it to the printer as is
*/
pbmi = BIT_Make_DIB_RGB_Header_24BIT(img->width, img->height, img->data);
}
else
{
/*
The image should already be in DIB_RGB_COLORS format. In
anything other than 8 bit mode, all images are stored that
way. In 8 bit mode, placeholder images are
stored that way. In either case, we need to reconstruct
a new DIB_RGB_COLORS, so that we can properly handle any
transparent colors.
*/
pbmi = BIT_Make_DIB_RGB_Header_Printer(img->width, img->height,
img->data, img->hPalette, img->transparent, img->flags);
}
}
err = StretchDIBits(hdc, XDest, YDest, nDestWidth, nDestHeight, XSrc, YSrc, nSrcWidth, nSrcHeight,
img->data, pbmi, DIB_RGB_COLORS, SRCCOPY);
GTR_FREE(pbmi);
return err;
}
void x_DisposeImage(struct ImageInfo *img)
{
if (img->hPalette)
DeleteObject(img->hPalette);
if (img->data)
{
GTR_FREE(img->data);
}
if (img->pbmi)
{
GTR_FREE(img->pbmi);
}
img->hPalette = NULL;
img->data = NULL;
img->pbmi = NULL;
}
int HT_CreateDeviceImageMap(struct Mwin *tw, struct ImageInfo *pImg)
{
/* free any previous versions */
if (pImg->pbmi)
GTR_FREE(pImg->pbmi);
if (wg.eColorMode == 8)
{
#ifdef FEATURE_JPEG
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_PAL_Header_Prematched(pImg->width,
pImg->height, pImg->data, pImg->flags);
pImg->flags |= IMG_PREMATCHED;
}
else
#endif
{
pImg->pbmi = BIT_Make_DIB_PAL_Header_Prematched(pImg->width,
pImg->height, pImg->data, pImg->flags);
pImg->transparent = BACKGROUND_COLOR_INDEX;
pImg->flags |= IMG_PREMATCHED;
}
}
else
{
if (wg.eColorMode == 4)
{
#ifdef FEATURE_JPEG
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_VGA(pImg->width,
pImg->height, pImg->data);
}
else
#endif
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_Screen(pImg->width,
pImg->height, pImg->data, pImg->hPalette,
pImg->transparent, pImg->flags);
}
}
else
{
#ifdef FEATURE_JPEG
/* true color display */
if (pImg->flags & IMG_JPEG)
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_24BIT(pImg->width,
pImg->height, pImg->data);
}
else
#endif
{
pImg->pbmi = BIT_Make_DIB_RGB_Header_Screen(pImg->width,
pImg->height, pImg->data, pImg->hPalette,
pImg->transparent, pImg->flags);
}
}
}
return (0);
}
/*
This function needs to be called whenever the background
color of the windows changes.
*/
void Image_UpdateTransparentColors(void)
{
int i;
int count;
struct ImageInfo *img;
LOGPALETTE *lp;
COLORREF colorWnd;
extern struct hash_table gImageCache;
count = Hash_Count(&gImageCache);
for (i = 0; i < count; i++)
{
Hash_GetIndexedEntry(&gImageCache, i, NULL, NULL, (void **) &img);
if ((img->hPalette && (img->transparent != -1)) || (img->flags & IMG_BW))
{
/*
The previous DIB is useless. Remove it
*/
if (img->pbmi)
{
GTR_FREE(img->pbmi);
}
img->pbmi = NULL;
if (img->hPalette)
{
/*
We need to replace the old palette with a new one
which has one entry modified.
*/
lp = (LOGPALETTE *) GTR_MALLOC(sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256);
if (lp)
{
lp->palVersion = 0x300;
lp->palNumEntries = 256;
/*
Get the old entries
*/
GetPaletteEntries(img->hPalette, 0, 256, lp->palPalEntry);
DeleteObject(img->hPalette);
colorWnd = PREF_GetBackgroundColor();
lp->palPalEntry[img->transparent].peRed = GetRValue(colorWnd);
lp->palPalEntry[img->transparent].peGreen = GetGValue(colorWnd);
lp->palPalEntry[img->transparent].peBlue = GetBValue(colorWnd);
img->hPalette = CreatePalette(lp);
GTR_FREE(lp);
}
else
{
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
img->hPalette = NULL;
}
}
img->pbmi = BIT_Make_DIB_RGB_Header_Screen(img->width, img->height,
img->data, img->hPalette, img->transparent, img->flags);
}
}
}
int GTR_StretchDIBits(
struct Mwin *tw,
HDC hdc, // handle of device context
RECT rect, // bounding rectangle of the image
int iBorder,// border width
int XSrc, // x-coordinate of upper-left corner of source rect.
int YSrc, // y-coordinate of upper-left corner of source rect.
int nSrcWidth, // width of source rectangle
int nSrcHeight, // height of source rectangle
CONST VOID *lpBits, // address of bitmap bits
CONST BITMAPINFO * lpBitsInfo, // address of bitmap data
UINT iUsage, // usage
DWORD dwRop, // raster operation code
int transparent // index of transparent color in DIB
)
{
HBITMAP hBitmap = NULL;
COLORREF color;
RGBQUAD transcolor;
PALETTEENTRY pal[256];
RECT temprect;
int result, offsetx, offsety;
if (transparent != -1)
{
/* Transparent color specified */
hBitmap = CreateDIBitmap(hdc, (CONST BITMAPINFOHEADER *) lpBitsInfo, CBM_INIT,
lpBits, lpBitsInfo, iUsage);
}
temprect = rect;
InflateRect(&temprect, -iBorder, -iBorder);
if (!hBitmap)
{
if (tw)
{
offsetx = tw->offl;
offsety = tw->offt;
}
else
{
offsetx = 0;
offsety = 0;
}
result = StretchDIBits(hdc, temprect.left - offsetx, temprect.top - offsety,
temprect.right - temprect.left, temprect.bottom - temprect.top,
XSrc, YSrc, nSrcWidth, nSrcHeight, lpBits, lpBitsInfo, iUsage, dwRop);
return result;
}
if (wg.eColorMode != 8)
{
transcolor = lpBitsInfo->bmiColors[transparent];
color = PALETTERGB(transcolor.rgbRed, transcolor.rgbGreen, transcolor.rgbBlue);
}
else
{
GetPaletteEntries(hPalGuitar, 0, 256, pal);
color = PALETTERGB(pal[transparent].peRed, pal[transparent].peGreen, pal[transparent].peBlue);
}
DrawTransparentBasedOnIndex(tw, hdc, temprect, XSrc, YSrc,
nSrcWidth, nSrcHeight, lpBits, lpBitsInfo, iUsage, dwRop, transparent);
DeleteObject(hBitmap);
return lpBitsInfo->bmiHeader.biHeight;
}
int DrawTransparentBasedOnIndex(
struct Mwin *tw,
HDC hdc, // handle of device context
RECT rect, // bounding rectangle
int XSrc, // x-coordinate of upper-left corner of source rect.
int YSrc, // y-coordinate of upper-left corner of source rect.
int nSrcWidth, // width of source rectangle
int nSrcHeight, // height of source rectangle
CONST VOID *lpBits, // address of bitmap bits
CONST BITMAPINFO * lpBitsInfo, // address of bitmap data
UINT iUsage, // usage
DWORD dwRop, // raster operation code
int transparent // index of transparent color in DIB
)
{
HBITMAP hBitmap, hOldBitmap;
HDC hdcMem;
int i, width, height;
WORD save_colors[256];
WORD *pw;
RGBQUAD save_quad[256];
RGBQUAD *pq;
HPALETTE hOldPal = NULL;
HBRUSH hBrush;
RECT temprect;
int offsetx, offsety;
/*
This technique is explained on the developer CD in an article called Bitmaps and Transparency, or something
like that.
*/
if (wg.eColorMode == 8)
{
pw = (WORD *) lpBitsInfo->bmiColors;
//
// BUGBUG: Spyglass jumped straight into the code below,
// without making sure that bmiColors had 256
// elements. This is not true for e.g. monochrome
// bitmaps, who have but 2. Looking through the code,
// it seems that monochrome is indeed the only case
// to worry about here, but this may require further
// investigation. Maybe this causes weird
// transparency results on some bitmaps
//
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
for (i = 0; i < 256; i++)
{
save_colors[i] = pw[i];
pw[i] = 0;
}
pw[transparent] = LAST_MAIN_PALETTE_COLOR;
}
}
else
{
//
// Save a copy of the color table
//
//
// See BUGBUG notice above.
//
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
pq = (RGBQUAD *) lpBitsInfo->bmiColors;
memcpy(save_quad, pq, 256 * sizeof(RGBQUAD));
// Create a black mask
for (i = 0; i < 256; i++)
{
pq[i].rgbRed = 0;
pq[i].rgbBlue = 0;
pq[i].rgbGreen = 0;
}
// Create a white mask for transparent colors
pq[transparent].rgbRed = 255;
pq[transparent].rgbBlue = 255;
pq[transparent].rgbGreen = 255;
}
}
// Prepare an off-screen bitmap
hdcMem = CreateCompatibleDC(hdc);
if (wg.eColorMode == 8)
{
hOldPal = SelectPalette(hdcMem, hPalGuitar, FALSE);
RealizePalette(hdcMem);
}
width = rect.right - rect.left;
height = rect.bottom - rect.top;
hBitmap = CreateCompatibleBitmap(hdc, width, height);
hOldBitmap = SelectObject(hdcMem, hBitmap);
// Grab the screen image into the off-screen bitmap
if (tw && tw->w3doc)
{
if (!gPrefs.bIgnoreDocumentAttributes && tw->w3doc->piiBackground && tw->w3doc->piiBackground->pbmi)
{
// Get a clean copy of the background
DrawBackgroundImage(tw, hdcMem, rect, rect.left, rect.top);
}
else
{
// Set the background color to the specified color
temprect.left = 0;
temprect.right = width;
temprect.top = 0;
temprect.bottom = height;
if (!gPrefs.bIgnoreDocumentAttributes && tw->w3doc->lFlags & W3DOC_FLAG_COLOR_BGCOLOR)
hBrush = CreateSolidBrush(tw->w3doc->color_bgcolor);
else if (!gPrefs.bUseSystemColors)
hBrush = CreateSolidBrush(gPrefs.window_bgcolor);
else
hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
FillRect(hdcMem, &temprect, hBrush);
DeleteObject(hBrush);
}
}
else
{
// If there is no tw, then simply use white as the background.
if (wg.eColorMode != 8)
{
temprect.left = 0;
temprect.right = width;
temprect.top = 0;
temprect.bottom = height;
hBrush = CreateSolidBrush(gPrefs.window_bgcolor);
FillRect(hdcMem, &temprect, hBrush);
DeleteObject(hBrush);
}
}
// BitBlt(hdcMem, 0, 0, nDestWidth, nDestHeight, hdc, XDest, YDest, SRCCOPY);
// Put the mask on the destination
StretchDIBits(hdcMem, 0, 0, width, height,
XSrc, YSrc, nSrcWidth, nSrcHeight, lpBits, lpBitsInfo, iUsage, SRCAND);
if (wg.eColorMode == 8)
{
//
// See bugbug on bitcounts
//
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
for (i = 0; i < 256; i++)
{
pw[i] = save_colors[i];
}
pw[transparent] = 0; /* black */
}
}
else
{
//
// Restore original colors
//
// See BUGBUG notice above
//
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
memcpy(pq, save_quad, 256 * sizeof(RGBQUAD));
// Change transparent black
pq[transparent].rgbRed = 0;
pq[transparent].rgbBlue = 0;
pq[transparent].rgbGreen = 0;
}
}
StretchDIBits(hdcMem, 0, 0, width, height,
XSrc, YSrc, nSrcWidth, nSrcHeight, lpBits, lpBitsInfo, iUsage, SRCPAINT);
if (wg.eColorMode == 8)
{
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
pw[transparent] = save_colors[transparent];
}
}
else
{
if (lpBitsInfo->bmiHeader.biBitCount != 1
&& lpBitsInfo->bmiColors != NULL)
{
pq[transparent] = save_quad[transparent];
}
}
if (hOldPal)
SelectPalette(hdcMem, hOldPal, FALSE);
SelectObject(hdcMem, hOldBitmap);
DeleteObject(hdcMem);
if (tw)
{
offsetx = tw->offl;
offsety = tw->offt;
}
else
{
offsetx = 0;
offsety = 0;
}
DrawBitmap(hdc, hBitmap, rect.left - offsetx, rect.top - offsety, width, height);
DeleteObject(hBitmap);
return 0;
}
void DrawTransparentBasedOnColor(HDC hdc, HBITMAP hBitmap, short xStart,
short yStart, COLORREF cTransparentColor)
{
BITMAP bm;
COLORREF cColor;
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
POINT ptSize;
hdcTemp = CreateCompatibleDC(hdc);
SelectPalette(hdcTemp, hPalGuitar, FALSE);
RealizePalette(hdcTemp);
SelectObject(hdcTemp, hBitmap); // Select the bitmap
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
ptSize.x = bm.bmWidth; // Get width of bitmap
ptSize.y = bm.bmHeight; // Get height of bitmap
DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
// to logical points
// Create some DCs to hold temporary data.
hdcBack = CreateCompatibleDC(hdc);
hdcObject = CreateCompatibleDC(hdc);
hdcMem = CreateCompatibleDC(hdc);
hdcSave = CreateCompatibleDC(hdc);
SelectPalette(hdcBack, hPalGuitar, FALSE);
SelectPalette(hdcObject, hPalGuitar, FALSE);
SelectPalette(hdcMem, hPalGuitar, FALSE);
SelectPalette(hdcSave, hPalGuitar, FALSE);
RealizePalette(hdcBack);
RealizePalette(hdcObject);
RealizePalette(hdcMem);
RealizePalette(hdcSave);
// Create a bitmap for each DC. DCs are required for a number of
// GDI functions.
// Monochrome DC
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
// Monochrome DC
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
// Each DC must select a bitmap object to store pixel data.
bmBackOld = SelectObject(hdcBack, bmAndBack);
bmObjectOld = SelectObject(hdcObject, bmAndObject);
bmMemOld = SelectObject(hdcMem, bmAndMem);
bmSaveOld = SelectObject(hdcSave, bmSave);
// Set proper mapping mode.
SetMapMode(hdcTemp, GetMapMode(hdc));
// Save the bitmap sent here, because it will be overwritten.
BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC to the color.
// contained in the parts of the bitmap that should be transparent
cColor = SetBkColor(hdcTemp, cTransparentColor);
// Create the object mask for the bitmap by performing a BitBlt
// from the source bitmap to a monochrome bitmap.
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
SRCCOPY);
// Set the background color of the source DC back to the original
// color.
SetBkColor(hdcTemp, cColor);
// Create the inverse of the object mask.
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
NOTSRCCOPY);
// Copy the background of the main DC to the destination.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,
SRCCOPY);
// Mask out the places where the bitmap will be placed.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
// Mask out the transparent colored pixels on the bitmap.
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
// XOR the bitmap with the background on the destination DC.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
// Copy the destination to the screen.
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,
SRCCOPY);
// Place the original bitmap back into the bitmap sent here.
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
// Delete the memory bitmaps.
DeleteObject(SelectObject(hdcBack, bmBackOld));
DeleteObject(SelectObject(hdcObject, bmObjectOld));
DeleteObject(SelectObject(hdcMem, bmMemOld));
DeleteObject(SelectObject(hdcSave, bmSaveOld));
// Delete the memory DCs.
DeleteDC(hdcMem);
DeleteDC(hdcBack);
DeleteDC(hdcObject);
DeleteDC(hdcSave);
DeleteDC(hdcTemp);
}
void DrawBitmap(HDC hDC, HBITMAP hBitmap, int x, int y, int width, int height)
{
HDC hMemDC;
HBITMAP hOldBitmap;
hMemDC = CreateCompatibleDC(hDC);
hOldBitmap = SelectObject(hMemDC, hBitmap);
BitBlt(hDC, x, y, width, height, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
void DrawBackgroundImage(struct Mwin *tw, HDC hdc, RECT rect, int offsetx, int offsety)
{
int beginx, beginy, transIndex;
COLORREF bgcolor;
int x, y, width, height;
HBITMAP hBitmap, hOldBitmap;
HDC hMemDC;
PALETTEENTRY trans_entry;
// Fill the rectangle with the background image. The rectangle
// is assumed to contain absolute Mosaic coordinates (offl and
// offt should have been added)
// If there is transparent color, replace its value with the current
// background color. This should result in faster performance than
// painting transparently on top of the screen.
transIndex = tw->w3doc->piiBackground->transparent;
if (transIndex != -1)
{
if (!gPrefs.bIgnoreDocumentAttributes && tw->w3doc->lFlags & W3DOC_FLAG_COLOR_BGCOLOR)
bgcolor = tw->w3doc->color_bgcolor;
else if (!gPrefs.bUseSystemColors)
bgcolor = gPrefs.window_bgcolor;
else
bgcolor = GetSysColor(COLOR_WINDOW);
if (wg.eColorMode == 8)
{
/* transIndex is the index of the RGBQUAD structure which contains
a 16-bit word index into the currently realized palette. */
GetPaletteEntries(hPalGuitar, transIndex, 1, &trans_entry);
if (trans_entry.peRed != GetRValue(bgcolor) ||
trans_entry.peBlue != GetBValue(bgcolor) ||
trans_entry.peGreen != GetGValue(bgcolor))
{
trans_entry.peRed = GetRValue(bgcolor);
trans_entry.peBlue = GetBValue(bgcolor);
trans_entry.peGreen = GetGValue(bgcolor);
trans_entry.peFlags = 0;
SetPaletteEntries(hPalGuitar, transIndex, 1, &trans_entry);
RealizePalette(hdc);
}
}
else
{
tw->w3doc->piiBackground->pbmi->bmiColors[transIndex].rgbRed = GetRValue(bgcolor);
tw->w3doc->piiBackground->pbmi->bmiColors[transIndex].rgbBlue = GetBValue(bgcolor);
tw->w3doc->piiBackground->pbmi->bmiColors[transIndex].rgbGreen = GetGValue(bgcolor);
}
}
hBitmap = CreateDIBitmap(hdc,
(CONST BITMAPINFOHEADER *) tw->w3doc->piiBackground->pbmi,
CBM_INIT,
tw->w3doc->piiBackground->data,
tw->w3doc->piiBackground->pbmi,
(wg.eColorMode == 8 ? DIB_PAL_COLORS : DIB_RGB_COLORS));
if (hBitmap)
{
hMemDC = CreateCompatibleDC(hdc);
hOldBitmap = SelectObject(hMemDC, hBitmap);
}
// Find beginning painting coordinate
width = tw->w3doc->piiBackground->width;
height = tw->w3doc->piiBackground->height;
beginx = width * (rect.left / width);
beginy = height * (rect.top / height);
for (y = beginy; y <= rect.bottom; y += height)
{
for (x = beginx; x <= rect.right; x += width)
{
if (hBitmap)
BitBlt(hdc, x - offsetx, y - offsety, width, height, hMemDC, 0, 0, SRCCOPY);
else
{
StretchDIBits(hdc, x - offsetx, y - offsety,
width, height, 0, 0, width, height,
tw->w3doc->piiBackground->data, tw->w3doc->piiBackground->pbmi,
(wg.eColorMode == 8 ? DIB_PAL_COLORS : DIB_RGB_COLORS), SRCCOPY);
}
}
}
if (hBitmap)
{
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
DeleteObject(hBitmap);
}
}
BOOL SaveAsBitmap(char *filename, BITMAPINFOHEADER *pbi, void *pdata)
{
BITMAPFILEHEADER bf;
int adjustedwidth, written;
FILE *fp;
adjustedwidth = pbi->biWidth * pbi->biBitCount / 8;
if (adjustedwidth % 4)
adjustedwidth += (4 - (adjustedwidth % 4));
memcpy(&bf.bfType, "BM", 2);
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
pbi->biHeight * adjustedwidth;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (pbi->biBitCount == 8)
{
bf.bfSize += (256 * sizeof(RGBQUAD));
bf.bfOffBits += (256 * sizeof(RGBQUAD));
}
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
// Ok, now save
fp = fopen(filename, "wb");
if (!fp)
{
ERR_ReportError(NULL, SID_ERR_COULD_NOT_SAVE_FILE_S, filename, NULL);
return FALSE;
}
written = fwrite(&bf, sizeof(bf), 1, fp);
if (written != 1)
goto UnableToSave;
if (pbi->biBitCount == 8)
{
if (wg.eColorMode == 8)
{
PALETTEENTRY pal[256];
RGBQUAD rgb[256];
int index;
// Retrieve the currently realized palette since we use indices for 256-color images.
// Indices cannot be saved in the bitmap file - actual RGB values must be saved instead.
GetPaletteEntries(hPalGuitar, 0, 256, pal);
// Convert PALETTEENTRY to RGBQUAD
memset(&rgb, 0, sizeof(rgb));
for (index = 0; index < 256; index++)
{
rgb[index].rgbRed = pal[index].peRed;
rgb[index].rgbBlue = pal[index].peBlue;
rgb[index].rgbGreen = pal[index].peGreen;
}
written = fwrite(pbi, 1, sizeof(BITMAPINFOHEADER), fp);
if (written != sizeof(BITMAPINFOHEADER))
goto UnableToSave;
written = fwrite(rgb, sizeof(RGBQUAD), 256, fp);
if (written != 256)
goto UnableToSave;
}
else
{
written = fwrite(pbi, 1, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD), fp);
if (written != sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD))
goto UnableToSave;
}
}
else
{
written = fwrite(pbi, 1, sizeof(BITMAPINFOHEADER), fp);
if (written != sizeof(BITMAPINFOHEADER))
goto UnableToSave;
}
written = fwrite(pdata, 1, pbi->biHeight * adjustedwidth, fp);
if (written != pbi->biHeight * adjustedwidth)
goto UnableToSave;
goto SkipError;
UnableToSave:
ERR_ReportError(NULL, SID_ERR_COULD_NOT_SAVE_FILE_S, filename, NULL);
SkipError:
fclose(fp);
return TRUE;
}