340 lines
9.1 KiB
C
340 lines
9.1 KiB
C
/****************************************************************************/
|
|
/* */
|
|
/* Microsoft Confidential */
|
|
/* */
|
|
/* Copyright (c) Microsoft Corp. 1987, 1991 */
|
|
/* 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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|