/****************************************************************************/ /* */ /* 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); }