/****************************************************************************/
/* */
/* Copyright (C) 1987-1996 Microsoft Corp. */
/* All Rights Reserved */
/* */
/****************************************************************************/
/****************************** Module Header *******************************
* Module Name: image.c
*
* Routines for manipulating images.
*
* History:
*
****************************************************************************/
#include "imagedit.h"
/************************************************************************
* ImageDCCreate
*
* Allocates the image DC's and bitmaps used to hold the current image
* being edited. This includes ghdcImage and ghbmImage. For icons and
* cursors, also allocates the DC and bitmap that holds the AND mask
* that contains information about whether any given pixel is screen
* color, inverted screen color or a true color. These globals are
* ghdcANDMask and ghbmANDMask.
*
* The image DC will contain the image as it will appear when displayed.
* For icons and cursors, this means that it is the combined XOR and AND
* portions of the image. When the icon/cursor file is saved, the bits
* will be separated back out, but having them combined in the image
* makes it fast to display the image while editing. Because of this,
* however, care must be taken when changing the screen color because
* it is not possible to determine from the image DC alone whether a
* pixel is screen color or simply a true color that happens to be the
* same as the current screen color. The AND mask is very important for
* keeping this straight and must be properly updated when drawing on
* the image DC with any of the drawing tools!
*
* Arguments:
* INT iType - Type of image.
* INT cx - Width of the image.
* INT cy - Height of the image.
* INT nColors - Number of colors.
*
* Returns TRUE if successful, or FALSE if an error occurs.
*
* History:
*
************************************************************************/
BOOL ImageDCCreate(
INT iType,
INT cx,
INT cy,
INT nColors)
{
HDC hdcParent;
/*
* Delete the old image DC's.
*/
ImageDCDelete();
hdcParent = GetDC(ghwndMain);
if (!(ghdcImage = CreateCompatibleDC(hdcParent)))
goto Error1;
if (!(ghbmImage = MyCreateBitmap(hdcParent, cx, cy, 16)))
goto Error2;
SelectObject(ghdcImage, ghbmImage);
/*
* If image is an icon or cursor, also allocate the AND mask
* DC and bitmap. Note that this cannot be a DIB (must use
* CreateBitmap) or the ImageDCSeparate() code will fail.
*/
if (iType == FT_ICON || iType == FT_CURSOR) {
if (!(ghdcANDMask = CreateCompatibleDC(hdcParent)))
goto Error2;
if (!(ghbmANDMask = CreateBitmap(cx, cy, (BYTE)1, (BYTE)1, NULL)))
goto Error3;
SelectObject(ghdcANDMask, ghbmANDMask);
}
ReleaseDC(ghwndMain, hdcParent);
/*
* Set some globals.
*/
gcxImage = cx;
gcyImage = cy;
gnColors = nColors;
/*
* Initialize the bits.
*/
ImageDCClear();
return TRUE;
Error3:
DeleteDC(ghdcANDMask);
ghdcANDMask = NULL;
Error2:
DeleteDC(ghdcImage);
ghdcImage = NULL;
Error1:
ReleaseDC(ghwndMain, hdcParent);
return FALSE;
}
/************************************************************************
* ImageDCDelete
*
* Deletes the current image DC. For icons and cursors, also deletes the
* mask DC. Finally, it destroys the undo buffers.
*
* History:
*
************************************************************************/
VOID ImageDCDelete(VOID)
{
if (ghdcImage) {
DeleteDC(ghdcImage);
ghdcImage = NULL;
DeleteObject(ghbmImage);
ghbmImage = NULL;
}
if (ghdcANDMask) {
DeleteDC(ghdcANDMask);
ghdcANDMask = NULL;
DeleteObject(ghbmANDMask);
ghbmANDMask = NULL;
}
/*
* Destroy the undo buffer.
*/
ImageFreeUndo();
}
/************************************************************************
* ImageDCClear
*
* Clears the image DC. Sets it to completely white. For icons and
* cursors, sets the image mask to be fully opaque also.
*
* History:
*
************************************************************************/
VOID ImageDCClear(VOID)
{
PatBlt(ghdcImage, 0, 0, gcxImage, gcyImage, WHITENESS);
/*
* For icons and cursors, set all the mask bits to zero.
*/
if (ghdcANDMask)
PatBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, BLACKNESS);
}
/************************************************************************
* ImageDCSeparate
*
* This function separates out the XOR mask in hdcImage so that it does
* not have any pixels that are screen/inverse color. This must be done
* prior to saving the image (or changing the screen color) because
* normally the hdcImage contains the image as it will be displayed,
* which is really a combined view of the XOR and AND masks. The function
* ImageDCCombine can be used after this function to combine the masks
* back together.
*
* History:
*
************************************************************************/
VOID ImageDCSeparate(
HDC hdcImage,
INT cx,
INT cy,
HDC hdcANDMask,
DWORD rgbScreen)
{
HBITMAP hbmTemp;
HDC hdcTemp;
HBITMAP hbmOld;
/*
* Create a temporary bitmap and DC for the mask bits and
* select bitmap into the DC.
*/
hdcTemp = CreateCompatibleDC(hdcImage);
hbmTemp = CreateCompatibleBitmap(hdcImage, cx, cy);
hbmOld = SelectObject(hdcTemp, hbmTemp);
/*
* Background color of temporary DC is set to the specified
* screen (transparent) color. The bits from mask DC (mono) are
* transferred to temp. DC (color). Thus the 1s in the mask (corresp.
* to "screen" and "inverse" portions) become "screen" colored pixels
* in temporary DC.
*/
SetBkColor(hdcTemp, rgbScreen);
BitBlt(hdcTemp, 0, 0, cx, cy, hdcANDMask, 0, 0, SRCCOPY);
/*
* The bits in the temporary DC are XORed against the bits in the image
* DC to recover the true XOR mask in hdcImage. The AND mask is already
* in hdcANDMask.
*/
BitBlt(hdcImage, 0, 0, cx, cy, hdcTemp, 0, 0, SRCINVERT);
SelectObject(hdcTemp, hbmOld);
DeleteDC(hdcTemp);
DeleteObject(hbmTemp);
}
/************************************************************************
* ImageDCCombine
*
* This function takes the raw XOR mask in hdcImage and combines
* it with the AND mask in hdcANDMask to put into hdcImage the
* current image as it will be displayed. This needs to be done after
* it is separated (just prior to saving the file and also when changing
* the screen color) and when the image is first opened.
*
* The current screen color in ghbrScreen is used when combining the
* image in this routine.
*
* History:
*
************************************************************************/
VOID ImageDCCombine(
HDC hdcImage,
INT cx,
INT cy,
HDC hdcANDMask)
{
HBITMAP hbmTemp;
HDC hdcTemp;
HBITMAP hbmOld;
HBRUSH hbrOld;
/*
* Make a copy of the image DC with the XOR mask in it.
*/
hdcTemp = CreateCompatibleDC(hdcImage);
hbmTemp = CreateCompatibleBitmap(hdcImage, cx, cy);
hbmOld = SelectObject(hdcTemp, hbmTemp);
BitBlt(hdcTemp, 0, 0, cx, cy, hdcImage, 0, 0, SRCCOPY);
/*
* Clear the image DC to the current screen color.
*/
hbrOld = SelectObject(hdcImage, ghbrScreen);
PatBlt(hdcImage, 0, 0, cx, cy , PATCOPY);
SelectObject(hdcImage, hbrOld);
/*
* Reconstruct the image by superimposing the XOR and AND masks.
*/
BitBlt(hdcImage, 0, 0, cx, cy, hdcANDMask, 0, 0, SRCAND);
BitBlt(hdcImage, 0, 0, cx, cy, hdcTemp, 0, 0, SRCINVERT);
SelectObject(hdcTemp, hbmOld);
DeleteDC(hdcTemp);
DeleteObject(hbmTemp);
}
/************************************************************************
* ImageDCMonoBlt
*
* This function blts an image onto a monochrome bitmap, then back
* again. This converts it to a monochrome image.
*
* History:
*
************************************************************************/
VOID ImageDCMonoBlt(
HDC hdcImage,
INT cx,
INT cy)
{
HBITMAP hbmTemp;
HDC hdcTemp;
HBITMAP hbmOld;
/*
* Create a temporary monochrome bitmap and dc.
*/
hdcTemp = CreateCompatibleDC(hdcImage);
hbmTemp = MyCreateBitmap(hdcImage, cx, cy, 2);
hbmOld = SelectObject(hdcTemp, hbmTemp);
/*
* Blt the image to the mono bitmap, then back again.
*/
BitBlt(hdcTemp, 0, 0, cx, cy, hdcImage, 0, 0, SRCCOPY);
BitBlt(hdcImage, 0, 0, cx, cy, hdcTemp, 0, 0, SRCCOPY);
/*
* Cleanup.
*/
SelectObject(hdcTemp, hbmOld);
DeleteObject(hbmTemp);
DeleteDC(hdcTemp);
}