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.
 
 
 
 
 
 

1082 lines
28 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Eric W. Sink [email protected]
*/
#include "all.h"
struct ImageInfo iiNotLoaded =
{ 32000, // refCount;
0, // width;
0, // height;
0, // flags;
NULL, // srcURL;
NULL, // actualURL;
NULL, // hPalette;
NULL, // pbmi;
NULL, // data;
-1, // transparent;
0, // cbImgLoadCount;
NULL, // decoderObject;
0, // cbCheckSum;
NULL // pImgOtherVers;
};
struct ImageInfo iiMissing =
{ 32000, // refCount;
0, // width;
0, // height;
0, // flags;
NULL, // srcURL;
NULL, // actualURL;
NULL, // hPalette;
NULL, // pbmi;
NULL, // data;
-1, // transparent;
0, // cbImgLoadCount;
NULL, // decoderObject;
0, // cbCheckSum;
NULL // pImgOtherVers;
};
void *pCreateDitherData(int xsize)
{
int *v_rgb_mem;
v_rgb_mem = (int *) GTR_CALLOC(3*(xsize + 2), sizeof(int));
return v_rgb_mem;
}
/*
constrains colors to 6X6X6 cube we use
*/
void x_ColorConstrain(unsigned char *psrc, unsigned char *pdst, PALETTEENTRY *pe, int xsize, int transparent)
{
int r_level, g_level, b_level;
int x;
int pixel;
for (x = 0; x < xsize; x++)
{
pixel = *psrc++;
if ((transparent != -1) && (pixel == transparent))
{
pixel = TRANSPARENT_COLOR_INDEX;
}
else
{
/* adjust red to the closest available value */
r_level = (pe[pixel].peRed + (RED_LEVEL_INCR/2)) / RED_LEVEL_INCR;
if (r_level < 0)
{
r_level = 0;
}
else if (r_level >= RED_COLOR_LEVELS)
{
r_level = RED_COLOR_LEVELS - 1;
}
/* adjust green to the closest available value */
g_level = (pe[pixel].peGreen + (GREEN_LEVEL_INCR/2)) / GREEN_LEVEL_INCR;
if (g_level < 0)
{
g_level = 0;
}
else if (g_level >= GREEN_COLOR_LEVELS)
{
g_level = GREEN_COLOR_LEVELS - 1;
}
/* adjust blue to the closest available value */
b_level = (pe[pixel].peBlue + (BLUE_LEVEL_INCR/2)) / BLUE_LEVEL_INCR;
if (b_level < 0)
{
b_level = 0;
}
else if (b_level >= BLUE_COLOR_LEVELS)
{
b_level = BLUE_COLOR_LEVELS - 1;
}
/*
Having calculated new r, g, and b values (along with their errors),
now we calculate the new pixel value
*/
pixel = CUBE6COLOR(r_level*GREEN_COLOR_LEVELS*BLUE_COLOR_LEVELS + g_level*BLUE_COLOR_LEVELS + b_level);
}
*pdst++ = pixel;
}
}
/*
Floyd-Steinberg error diffusion dithering routine
*/
void x_DitherRelative(unsigned char *pdata, PALETTEENTRY *pe, int xsize, int ysize, int transparent, int *v_rgb_mem, int yfirst, int ylast)
{
int *v_red;
int *v_grn;
int *v_blu;
int h_red;
int h_grn;
int h_blu;
int x;
int y;
int r,g,b;
int r2,g2,b2;
int r_level, g_level, b_level;
int total_error;
int padWidth;
unsigned char *p;
int xstart;
int xend;
int xinc;
int red_next_error;
int grn_next_error;
int blu_next_error;
if (xsize%4) {
padWidth = xsize + 4 - (xsize%4);
}
else {
padWidth = xsize;
}
/* Initially, the vertical errors are 0, set by calloc */
v_red = v_rgb_mem + 1;
v_grn = v_red + (xsize+2);
v_blu = v_grn + (xsize+2);
for (y=yfirst; y<= ylast; y++)
{
/* Beginning each new row, the horizontal errors are 0 */
h_red = 0;
h_grn = 0;
h_blu = 0;
red_next_error = 0;
grn_next_error = 0;
blu_next_error = 0;
p = pdata + padWidth*(ysize - y - 1); /* the DIB is stored upside down */
xstart = 0;
xend = xsize;
xinc = 1;
/*
Dithering currently only works left to right. If we wanted bidirectional
dithering, we would need to set:
xstart = xsize-1;
xend = -1;
xinc = -1;
*/
for (x = xstart; x != xend; x += xinc)
{
if ((transparent != -1) && (*p == transparent))
{
h_red = 0;
h_grn = 0;
h_blu = 0;
v_red[x] = 0;
v_grn[x] = 0;
v_blu[x] = 0;
*p = TRANSPARENT_COLOR_INDEX;
}
else
{
/* RED */
/* r is the original value adjusted with the previous vertical and horizontal errors */
r = pe[*p].peRed + (h_red + v_red[x]);
/* adjust r to the closest available value */
r_level = (r + (RED_LEVEL_INCR/2)) / RED_LEVEL_INCR;
if (r_level < 0)
{
r_level = 0;
}
else if (r_level >= RED_COLOR_LEVELS)
{
r_level = RED_COLOR_LEVELS - 1;
}
r2 = r_level * RED_LEVEL_INCR;
/* calculate the errors for the current pixel, total error is (r - r2) */
total_error = (r - r2); /* 1/16 */
v_red[x-xinc] += (total_error * 3 / 16);
v_red[x] = (total_error * 5 / 16) + red_next_error; /* from the previous column */
red_next_error = (total_error / 16);
h_red = (r - r2) - (total_error * 9 / 16);
/* GREEN */
/* g is the original value adjusted with the previous vertical and horizontal errors */
g = pe[*p].peGreen + (h_grn + v_grn[x]);
/* adjust g to the closest available value */
g_level = (g + (GREEN_LEVEL_INCR/2)) / GREEN_LEVEL_INCR;
if (g_level < 0)
{
g_level = 0;
}
else if (g_level >= GREEN_COLOR_LEVELS)
{
g_level = GREEN_COLOR_LEVELS - 1;
}
g2 = g_level * GREEN_LEVEL_INCR;
/* calculate the errors for the current pixel, total error is (g - g2) */
total_error = (g - g2); /* 1/16 */
v_grn[x-xinc] += (total_error * 3 / 16);
v_grn[x] = (total_error * 5 / 16) + grn_next_error; /* from the previous column */
grn_next_error = (total_error / 16);
h_grn = (g - g2) - (total_error * 9 / 16);
/* BLUE */
/* b is the original value adjusted with the previous vertical and horizontal errors */
b = pe[*p].peBlue + (h_blu + v_blu[x]);
/* adjust b to the closest available value */
b_level = (b + (BLUE_LEVEL_INCR/2)) / BLUE_LEVEL_INCR;
if (b_level < 0)
{
b_level = 0;
}
else if (b_level >= BLUE_COLOR_LEVELS)
{
b_level = BLUE_COLOR_LEVELS - 1;
}
b2 = b_level * BLUE_LEVEL_INCR;
/* calculate the errors for the current pixel, total error is (b - b2) */
total_error = (b - b2); /* 1/16 */
v_blu[x-xinc] += (total_error * 3 / 16);
v_blu[x] = (total_error * 5 / 16) + blu_next_error; /* from the previous column */
blu_next_error = (total_error / 16);
h_blu = (b - b2) - (total_error * 9 / 16);
/*
Having calculated new r, g, and b values (along with their errors),
now we calculate the new pixel value
*/
*p = CUBE6COLOR(r_level*GREEN_COLOR_LEVELS*BLUE_COLOR_LEVELS + g_level*BLUE_COLOR_LEVELS + b_level);
}
p++;
}
}
}
/*
Floyd-Steinberg error diffusion dithering routine
*/
static int x_Dither(unsigned char *pdata, PALETTEENTRY *pe, int xsize, int ysize, int transparent)
{
int *v_rgb_mem;
v_rgb_mem = (int *) pCreateDitherData(xsize);
if (!v_rgb_mem)
{
return -1;
}
x_DitherRelative(pdata,pe,xsize,ysize,transparent,v_rgb_mem,0,ysize-1);
GTR_FREE(v_rgb_mem);
return 0;
}
/*
This routine loads a bitmap from resources and constructs a DIB
in DIB_RGB_COLORS format for it.
*/
static BOOL x_load_dib(struct ImageInfo *pii, int rez)
{
BITMAP bmp;
HBITMAP hBitmap;
HDC hdc;
int padwidth;
hBitmap = LoadImage( wg.hInstance, MAKEINTRESOURCE(rez),
IMAGE_BITMAP, 0, 0, 0);
if (hBitmap && GetObject(hBitmap, sizeof(BITMAP), (LPVOID) & bmp))
{
if (pii->pbmi == NULL)
{
pii->pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
}
if (pii->pbmi)
{
pii->width = bmp.bmWidth;
pii->height = bmp.bmHeight;
pii->pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pii->pbmi->bmiHeader.biWidth = pii->width;
pii->pbmi->bmiHeader.biHeight = pii->height;
pii->pbmi->bmiHeader.biPlanes = 1;
pii->pbmi->bmiHeader.biBitCount = 8;
pii->pbmi->bmiHeader.biCompression = BI_RGB; /* no compression */
pii->pbmi->bmiHeader.biSizeImage = 0; /* not needed when not compressed */
pii->pbmi->bmiHeader.biXPelsPerMeter = 0;
pii->pbmi->bmiHeader.biYPelsPerMeter = 0;
pii->pbmi->bmiHeader.biClrUsed = 256;
pii->pbmi->bmiHeader.biClrImportant = 0;
padwidth = ((pii->width + 3) / 4) * 4;
if (pii->data == NULL)
{
pii->data = (unsigned char *) GTR_MALLOC(padwidth * pii->height);
}
if (pii->data)
{
hdc = GetDC(NULL);
GetDIBits(hdc, hBitmap, 0, pii->height, pii->data, pii->pbmi, DIB_RGB_COLORS);
ReleaseDC(NULL, hdc);
}
}
}
DeleteObject(hBitmap);
return pii->data == NULL || pii->pbmi == NULL ? TRUE : FALSE;
}
BOOL LoadImagePlaceholders(void)
{
BOOL bResult;
bResult = x_load_dib(&iiMissing, RES_IMAGE_MISSING);
return x_load_dib(&iiNotLoaded, RES_IMAGE_NOTLOADED) || bResult;
}
static void x_destroy_dib(struct ImageInfo *pii)
{
if (pii)
{
if (pii->data)
{
GTR_FREE(pii->data);
}
if (pii->pbmi)
{
GTR_FREE(pii->pbmi);
}
}
}
void DestroyImagePlaceholders(void)
{
x_destroy_dib(&iiMissing);
x_destroy_dib(&iiNotLoaded);
}
// Allocates and returns pbitmapinfo for 8 bit color image (depending on type
// of display
static PBITMAPINFO x_8BPIBitmap(int xsize, int ysize)
{
PBITMAPINFO pbmi;
if (wg.eColorMode == 8)
{
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;
}
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;
}
return pbmi;
}
/*
This routine should only be used when drawing to an 8 bit palette screen.
It always creates a DIB in DIB_PAL_COLORS format, and it handles the
case of a B/W image as well as color images. B/W images are created
with their pixels set to the foreground and background colors of the
screen, in the global palette. Color images are always dithered into
the global palette, and may have a transparent color.
*/
PBITMAPINFO BIT_Make_DIB_PAL_Header(int xsize, int ysize, CONST BYTE * pdata, HPALETTE hPalette, int transparent)
{
PALETTEENTRY pe[256];
int i;
PBITMAPINFO pbmi;
WORD *pw;
if (!hPalette)
{
pbmi = (PBITMAPINFO) GTR_MALLOC(sizeof(BITMAPINFOHEADER) + 2 * sizeof(DWORD));
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 = x_8BPIBitmap(xsize, ysize);
if (!pbmi)
{
return NULL;
}
GetPaletteEntries(hPalette, 0, 256, pe);
pw = (WORD *) pbmi->bmiColors;
if (pdata)
x_Dither((unsigned char *) pdata, pe, xsize, ysize, transparent);
for (i = 0; i < 256; i++)
{
pw[i] = i;
}
}
return pbmi;
}
/*
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, the only happens for JPEG images, since they arrive in
24 bit format, they are dithered into the global palette as they are read.
*/
#ifdef FEATURE_JPEG
PBITMAPINFO BIT_Make_DIB_PAL_Header_Prematched(int xsize, int ysize, CONST BYTE * pdata)
{
int i;
PBITMAPINFO pbmi;
WORD *pw;
{
pbmi = x_8BPIBitmap(xsize, ysize);
if (!pbmi)
{
return NULL;
}
pw = (WORD *) pbmi->bmiColors;
for (i = 0; i < 256; i++)
{
pw[i] = i;
}
}
return pbmi;
}
#endif /* FEATURE_JPEG */
/*
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 if ((flags & IMG_JPEG) && (wg.eColorMode != 8))
{
pbmi = BIT_Make_DIB_RGB_Header_24BIT(xsize, ysize, pdata);
}
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 = x_8BPIBitmap(xsize, ysize);
if (!pbmi)
{
return NULL;
}
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;
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, TRANSPARENT_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
{
/*
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;
}
// Performs a StretchDIBits patching bitmap color table as necessary to
// handle dibenv. we must patch the color table if we have a transparent
// image (which implies 8-bits per pixel) or black and white (iff 2 colors
// used in bitmap)
int MyStretchDIBits(
HDC hdc, // handle of device context
int XDest, // x-coordinate of upper-left corner of dest. rect.
int YDest, // y-coordinate of upper-left corner of dest. rect.
int nDestWidth, // width of destination rectangle
int nDestHeight, // height of destination 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, // bitmap bits
LPBITMAPINFO lpBitsInfo, // bitmap data
UINT iUsage, // usage
DWORD dwRop, // raster operation code
PDIBENV pdibenv // DIBENV for draw
)
{
RGBQUAD rgbFg;
RGBQUAD rgbBg;
int idxSaveFg;
int idxSaveBg;
BOOL bBandW = lpBitsInfo->bmiHeader.biClrUsed == 2;
BOOL bTransparent = pdibenv->transparent >= 0;
WORD *pw;
int result;
HDC hdcbm = NULL;
HBITMAP hbitmap = NULL;
RECT rectDC;
RECT rectDoc;
RECT rectScreen;
BOOL bErase = FALSE;
int XDDest = XDest;
int YDDest = YDest;
HDC dhdc = hdc;
struct Mwin *tw = pdibenv->tw;
PBITMAPINFO pbmi = NULL;
BOOL bPalette = (wg.eColorMode == 8);
int i;
static const RGBQUAD rgbWhite = {255, 255, 255, 0};
static const RGBQUAD rgbBlack = {0, 0, 0, 0};
// These define the biggest offscreen buffer we'll try to make
#define MAX_OSBUFFER (0x100000)
int destBytes;
SetStretchBltMode(hdc, COLORONCOLOR);
if (bBandW)
{
if (bPalette)
{
pw = (WORD *) lpBitsInfo->bmiColors;
idxSaveBg = pw[0];
idxSaveFg = pw[1];
pw[0] = colorIdxBg;
pw[1] = colorIdxFg;
}
else
{
rgbBg = lpBitsInfo->bmiColors[0];
rgbFg = lpBitsInfo->bmiColors[1];
lpBitsInfo->bmiColors[0].rgbRed = GetRValue(pdibenv->colorBg);
lpBitsInfo->bmiColors[0].rgbGreen = GetGValue(pdibenv->colorBg);
lpBitsInfo->bmiColors[0].rgbBlue = GetBValue(pdibenv->colorBg);
lpBitsInfo->bmiColors[1].rgbRed = GetRValue(pdibenv->colorFg);
lpBitsInfo->bmiColors[1].rgbGreen = GetGValue(pdibenv->colorFg);
lpBitsInfo->bmiColors[1].rgbBlue = GetBValue(pdibenv->colorFg);
}
}
else if (bTransparent)
{
if (bPalette)
{
pw = (WORD *) lpBitsInfo->bmiColors;
idxSaveBg = pw[TRANSPARENT_COLOR_INDEX];
pw[TRANSPARENT_COLOR_INDEX] = pdibenv->colorIdxBg;
}
else
{
rgbBg = lpBitsInfo->bmiColors[pdibenv->transparent];
lpBitsInfo->bmiColors[pdibenv->transparent].rgbRed = GetRValue(pdibenv->colorBg);
lpBitsInfo->bmiColors[pdibenv->transparent].rgbGreen = GetGValue(pdibenv->colorBg);
lpBitsInfo->bmiColors[pdibenv->transparent].rgbBlue = GetBValue(pdibenv->colorBg);
}
}
if (bTransparent &&
pdibenv->bFancyBg &&
(pbmi = x_8BPIBitmap(lpBitsInfo->bmiHeader.biWidth, lpBitsInfo->bmiHeader.biHeight)))
{
HDC savehdc;
rectDoc.left = XDest;
rectDoc.right = XDest + nDestWidth;
rectDoc.top = YDest;
rectDoc.bottom = YDest + nDestHeight;
IntersectRect(&rectScreen, &(pdibenv->rectPaint), &rectDoc);
rectDC.left = 0;
rectDC.top = 0;
rectDC.right = rectScreen.right - rectScreen.left;
rectDC.bottom = rectScreen.bottom - rectScreen.top;
// To avoid flashing, we set up memory DC so we can always draw opaquely
// If this operation fails due to lack of memory, we explictly draw background ourselves
// We don't do this if the offscreen bitmap would be bigger than MAX_OSBUFFER
if (tw->bErase)
{
destBytes = rectDC.right*rectDC.bottom*(wg.eColorMode / 8);
if (destBytes <= MAX_OSBUFFER)
{
hdcbm = CreateCompatibleDC(hdc);
if (hdcbm)
{
hbitmap = CreateCompatibleBitmap(hdc,rectDC.right,rectDC.bottom);
GTR_RealizePalette(hdcbm);
SelectObject(hdcbm, hbitmap);
SetStretchBltMode(hdcbm, COLORONCOLOR);
}
}
if (hdcbm == NULL || hbitmap == NULL)
{
if (hdcbm) DeleteDC(hdcbm);
hdcbm = NULL;
bErase = tw->bErase;
}
}
// bErase is TRUE, iff we didn't set up memory device context
if (bErase)
{
TW_DrawBackground(tw, tw->offl, tw->offt, 0, 0, &rectScreen);
}
else if (hdcbm != NULL)
{
savehdc = tw->hdc;
tw->hdc = hdcbm;
TW_DrawBackground(tw, tw->offl, tw->offt, rectScreen.left, rectScreen.top, &rectDC);
tw->hdc = savehdc;
dhdc = hdcbm;
XDDest = XDest - rectScreen.left;
YDDest = YDest - rectScreen.top;
}
// USE SRCAND to set bits in dest that will be covered by
// opaque bits to 0 and leave bits covered by transparent bits untouched
if (bPalette)
{
pw = (WORD *) pbmi->bmiColors;
for (i = 0;i < 256; i++)
pw[i] = CUBE6COLOR(0); // <0,0,0>
pw[TRANSPARENT_COLOR_INDEX] = CUBE6COLOR(LAST_MAIN_PALETTE_COLOR); // <255,255,255>
}
else
{
for (i= 0; i < 256; i++)
{
pbmi->bmiColors[i] = rgbBlack;
}
pbmi->bmiColors[pdibenv->transparent] = rgbWhite;
}
result = StretchDIBits(dhdc,
XDDest, YDDest, nDestWidth, nDestHeight,
XSrc, YSrc, nSrcWidth, nSrcHeight,
lpBits, pbmi,
iUsage, SRCAND);
// USE SRCPAINT == OR, to copy over just the opaque bits
if (bPalette)
{
pw = (WORD *) lpBitsInfo->bmiColors;
pw[TRANSPARENT_COLOR_INDEX] = CUBE6COLOR(0);
}
else
{
lpBitsInfo->bmiColors[pdibenv->transparent] = rgbBlack;
}
result = StretchDIBits(dhdc,
XDDest, YDDest, nDestWidth, nDestHeight,
XSrc, YSrc, nSrcWidth, nSrcHeight,
lpBits, lpBitsInfo,
iUsage, SRCPAINT);
// Finally, bitblt in composited image
if (hdcbm)
{
BitBlt(hdc,rectScreen.left,rectScreen.top,rectDC.right,rectDC.bottom,hdcbm,0,0,dwRop);
DeleteObject(hbitmap);
DeleteDC(hdcbm);
}
if (pbmi) GTR_FREE(pbmi);
}
else
{
result = StretchDIBits(hdc,
XDest, YDest, nDestWidth, nDestHeight,
XSrc, YSrc, nSrcWidth, nSrcHeight,
lpBits, lpBitsInfo,
iUsage, dwRop);
}
if (bBandW)
{
if (bPalette)
{
pw[0] = idxSaveBg;
pw[1] = idxSaveFg;
}
else
{
lpBitsInfo->bmiColors[0] = rgbBg;
lpBitsInfo->bmiColors[1] = rgbFg;
}
}
else if (bTransparent)
{
if (bPalette)
{
pw[TRANSPARENT_COLOR_INDEX] = idxSaveBg;
}
else
{
lpBitsInfo->bmiColors[pdibenv->transparent] = rgbBg;
}
}
return result;
}