mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
}
|