/****************************************************************************/
/* */
/* Copyright (C) 1987-1996 Microsoft Corp. */
/* All Rights Reserved */
/* */
/****************************************************************************/
/****************************** Module Header *******************************
* Module Name: image.c
*
* Routines for opening and saving images.
*
* History:
*
****************************************************************************/
#include "imagedit.h"
#include <stdio.h>
#include <string.h>
/************************************************************************
* ImageNew
*
* Creates a new image for the specified device.
*
* Arguments:
*
* History:
*
************************************************************************/
BOOL ImageNew(
PDEVICE pDevice)
{
PIMAGEINFO pImage;
if (!(pImage = ImageLinkAlloc(pDevice, pDevice->cx, pDevice->cy,
0, 0, pDevice->nColors)))
return FALSE;
/*
* Allocate work space for the new image.
*/
if (!ImageDCCreate(pDevice->iType, pImage->cx, pImage->cy,
pImage->nColors)) {
ImageLinkFree(pImage);
return FALSE;
}
gpImageCur = pImage;
gnImages++;
giType = pDevice->iType;
/*
* Initialize the pick rectangle to encompass the entire image.
*/
PickSetRect(0, 0, gcxImage - 1, gcyImage - 1);
/*
* Mark the newly created image as dirty to be sure it gets saved.
*/
fImageDirty = TRUE;
/*
* Update the palettes.
*/
SetColorPalette(gnColors, giType, FALSE);
PropBarUpdate();
ToolboxUpdate();
ViewReset();
/*
* Reset the workspace window and then show it.
*/
WorkReset();
ShowWindow(ghwndWork, SW_SHOWNORMAL);
return TRUE;
}
/************************************************************************
* ImageNewBitmap
*
* Creates a new bitmap image given a set of characteristics. After
* device link is created for those characteristics, ImageNew() is
* called to do the actual work.
*
* Arguments:
*
* History:
*
************************************************************************/
BOOL ImageNewBitmap(
INT cx,
INT cy,
INT nColors)
{
PDEVICE pDevice;
if (!(pDevice = DeviceLinkAlloc(FT_BITMAP, NULL, nColors, cx, cy)))
return FALSE;
return ImageNew(pDevice);
}
/************************************************************************
* ImageOpen
*
* Determines what has to be done to open the specified image. If it
* is not already the current image, it will save the current image
* then will call ImageOpen2() to open the new one.
*
* Arguments:
*
* History:
*
************************************************************************/
BOOL ImageOpen(
PIMAGEINFO pImage)
{
/*
* New image is already current. Return success.
*/
if (pImage == gpImageCur)
return TRUE;
/*
* Is this an image for a known device?
*/
if (pImage->pDevice) {
/*
* Save away the current image.
*/
ImageSave();
/*
* Do the real open of the new image.
*/
return ImageOpen2(pImage);
}
else {
Message(MSG_CANTEDITIMAGE);
return FALSE;
}
}
/************************************************************************
* ImageOpen2
*
* Unconditionally opens up the specified image for editing. This involves
* parsing the DIB into various globals, putting the bits onto the screen
* and updating the different palettes appropriately.
*
* Arguments:
*
* History:
*
************************************************************************/
BOOL ImageOpen2(
PIMAGEINFO pImage)
{
HCURSOR hcurOld;
LPBITMAPINFO lpbi;
INT iBitCount;
INT cx;
INT cy;
INT nColors;
DWORD cbColorTable;
DWORD cbBits;
LPBYTE lpDIBBits;
HBITMAP hbmMono;
HBITMAP hbmImage;
PBITMAPINFO pbi;
hcurOld = SetCursor(hcurWait);
lpbi = (LPBITMAPINFO)pImage->DIBPtr;
iBitCount = lpbi->bmiHeader.biBitCount;
cx = (INT)lpbi->bmiHeader.biWidth;
cy = (INT)lpbi->bmiHeader.biHeight;
if (giType != FT_BITMAP)
cy /= 2;
nColors = pImage->nColors;
/*
* Allocate work space for the image.
*/
if (!ImageDCCreate(giType, cx, cy, nColors))
goto Error1;
/*
* Create a temporary bitmap.
*/
if (!(hbmMono = CreateBitmap(1, 1, 1, 1, NULL))) {
Message(MSG_OUTOFMEMORY);
goto Error2;
}
cbColorTable = (1 << iBitCount) * sizeof(RGBQUAD);
lpDIBBits = (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) + cbColorTable;
cbBits = (((((DWORD)cx * iBitCount) + 31) & 0xffffffe0) >> 3) * cy;
/*
* Make a copy of the info header and color table.
*/
if (!(pbi = (PBITMAPINFO)MyAlloc(
sizeof(BITMAPINFOHEADER) + (INT)cbColorTable)))
goto Error3;
memcpy((LPBYTE)pbi, lpbi, sizeof(BITMAPINFOHEADER) + (INT)cbColorTable);
/* * Adjust some fields. The size field in an icon/cursor dib
* includes the AND mask bits, which we don't want to include
* right now.
*/
pbi->bmiHeader.biHeight = cy;
pbi->bmiHeader.biSizeImage = cbBits;
/*
* Set the bits into the XOR mask.
*/
hbmImage = SelectObject(ghdcImage, hbmMono);
SetDIBits(ghdcImage, hbmImage, 0, cy, lpDIBBits, pbi, DIB_RGB_COLORS);
SelectObject(ghdcImage, hbmImage);
/*
* If we are editing an icon or cursor, we need to set the bits
* for the AND mask also now.
*/
if (giType != FT_BITMAP) {
/*
* Skip past the XOR mask bits to the AND bits that follow.
*/
lpDIBBits += cbBits;
cbColorTable = 2 * sizeof(RGBQUAD);
/*
* Adjust some fields in the copy of the bitmap info structure,
* then copy a monochrome color table into it. Note that we
* are using the same allocated copy, which is ok because there
* will always be enough room allocated for the monochrome
* color table.
*/
pbi->bmiHeader.biBitCount = 1;
pbi->bmiHeader.biSizeImage =
cy * ((((DWORD)cx + 31) & 0xffffffe0) >> 3);
pbi->bmiHeader.biClrImportant = 0;
pbi->bmiHeader.biClrUsed = 0;
memcpy((PBYTE)pbi->bmiColors, (PBYTE)gargbColorTable2,
(INT)cbColorTable);
/*
* Set the bits into the AND mask.
*/
hbmImage = SelectObject(ghdcANDMask, hbmMono);
SetDIBits(ghdcANDMask, hbmImage, 0, cy, lpDIBBits, pbi,
DIB_RGB_COLORS);
SelectObject(ghdcANDMask, hbmImage);
/*
* Combine the XOR and AND masks into a viewable image.
*/
ImageDCCombine(ghdcImage, gcxImage, gcyImage, ghdcANDMask);
}
MyFree(pbi);
DeleteObject(hbmMono);
/*
* Set the current image pointer.
*/
gpImageCur = pImage;
fImageDirty = FALSE;
/*
* Initialize the pick rectangle to encompass the entire image.
*/
PickSetRect(0, 0, gcxImage - 1, gcyImage - 1);
SetColorPalette(gnColors, giType, FALSE);
/*
* Update the properties bar info and toolbox.
*/
PropBarUpdate();
ToolboxUpdate();
ViewReset();
/*
* Reset the workspace window and then show it.
*/
WorkReset();
ShowWindow(ghwndWork, SW_SHOWNORMAL);
SetCursor(hcurOld);
return TRUE;
Error3:
DeleteObject(hbmMono);
Error2:
ImageDCDelete();
Error1:
SetCursor(hcurOld);
return FALSE;
}
/************************************************************************
* ImageSave
*
* Saves the state of the current image into the image list (if it
* is dirty).
*
* History:
*
************************************************************************/
VOID ImageSave(VOID)
{
HCURSOR hcurOld;
INT iBitCount;
DWORD cbColorTable;
DWORD cbXORBits;
DWORD cbANDBits;
HANDLE hDIB;
DWORD dwDIBSize;
LPBITMAPINFOHEADER lpbih;
LPBYTE lpBits;
HBITMAP hbmMono;
HBITMAP hbmImage;
if (!fImageDirty)
return;
hcurOld = SetCursor(hcurWait);
/*
* Separate out the XOR and AND masks for ico/cur images.
*/
if (giType != FT_BITMAP)
ImageDCSeparate(ghdcImage, gcxImage, gcyImage, ghdcANDMask, grgbScreen);
/*
* Create a temporary bitmap.
*/
if (!(hbmMono = CreateBitmap(1, 1, 1, 1, NULL))) {
Message(MSG_OUTOFMEMORY);
goto Error1;
}
switch (gpImageCur->nColors) {
case 2:
iBitCount = 1;
break;
case 16:
iBitCount = 4;
break;
}
cbColorTable = (DWORD)gpImageCur->nColors * sizeof(RGBQUAD);
cbXORBits = (((((DWORD)gpImageCur->cx * iBitCount) + 31)
& 0xffffffe0) >> 3) * gpImageCur->cy;
switch (giType) {
case FT_BITMAP:
cbANDBits = 0;
break;
case FT_ICON:
case FT_CURSOR:
cbANDBits = (DWORD)gpImageCur->cy *
((((DWORD)gpImageCur->cx + 31) & 0xffffffe0) >> 3);
break;
}
dwDIBSize = sizeof(BITMAPINFOHEADER) + cbColorTable + cbXORBits +
cbANDBits;
/*
* Allocate space for the DIB for this image.
*/
if (!(hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize))) {
Message(MSG_OUTOFMEMORY);
goto Error2;
}
lpbih = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
/*
* For icons and cursors, we need to get the AND mask bits first.
*/
if (giType != FT_BITMAP) {
/*
* Point to where the AND bits should go.
*/
lpBits = (LPBYTE)lpbih + sizeof(BITMAPINFOHEADER) +
cbColorTable + cbXORBits;
/*
* Fill in the bitmap info header for getting the AND bits.
*/
lpbih->biSize = sizeof(BITMAPINFOHEADER);
lpbih->biWidth = gpImageCur->cx;
lpbih->biHeight = gpImageCur->cy;
lpbih->biPlanes = 1;
lpbih->biBitCount = 1;
lpbih->biCompression = BI_RGB;
lpbih->biSizeImage = cbANDBits;
lpbih->biXPelsPerMeter = 0;
lpbih->biYPelsPerMeter = 0;
lpbih->biClrImportant = 0;
lpbih->biClrUsed = 0;
/*
* Get the bits from the AND mask.
*/
hbmImage = SelectObject(ghdcANDMask, hbmMono);
GetDIBits(ghdcANDMask, hbmImage, 0, gpImageCur->cy, lpBits,
(LPBITMAPINFO)lpbih, DIB_RGB_COLORS);
SelectObject(ghdcANDMask, hbmImage);
}
/*
* Fill in the bitmap info header for getting the XOR bits.
*/
lpbih->biSize = sizeof(BITMAPINFOHEADER);
lpbih->biWidth = gpImageCur->cx;
lpbih->biHeight = gpImageCur->cy;
lpbih->biPlanes = 1;
lpbih->biBitCount = iBitCount;
lpbih->biCompression = BI_RGB;
lpbih->biSizeImage = cbXORBits;
lpbih->biXPelsPerMeter = 0;
lpbih->biYPelsPerMeter = 0;
lpbih->biClrImportant = 0;
lpbih->biClrUsed = 0;
/*
* Point to where the XOR bits should go.
*/
lpBits = (LPBYTE)lpbih + sizeof(BITMAPINFOHEADER) + cbColorTable;
/*
* Get the bits from the XOR mask.
*/
hbmImage = SelectObject(ghdcImage, hbmMono);
GetDIBits(ghdcImage, hbmImage, 0, gpImageCur->cy, lpBits,
(LPBITMAPINFO)lpbih, DIB_RGB_COLORS);
SelectObject(ghdcImage, hbmImage);
/*
* For icons and cursors, we have a few extra steps.
*/
if (giType != FT_BITMAP) {
/*
* Set the fields in the info structure to their final
* values. The saved value in the bitmap info header for the
* height in an icon/cursor DIB is really twice the height of
* the image, and the size of the image is the size of both
* the XOR and the AND mask bits.
*/
lpbih->biHeight *= 2;
lpbih->biSizeImage = cbXORBits + cbANDBits;
/*
* Recombine the XOR and AND masks now that we have their bits.
*/
ImageDCCombine(ghdcImage, gcxImage, gcyImage, ghdcANDMask);
}
/*
* Free any old DIB.
*/
if (gpImageCur->DIBhandle) {
GlobalUnlock(gpImageCur->DIBhandle);
GlobalFree(gpImageCur->DIBhandle);
}
/*
* Set the image structure to point to the newly created DIB.
*/
gpImageCur->DIBSize = dwDIBSize;
gpImageCur->DIBhandle = hDIB;
gpImageCur->DIBPtr = (LPBYTE)lpbih;
fFileDirty = TRUE;
fImageDirty = FALSE;
Error2:
DeleteObject(hbmMono);
Error1:
SetCursor (hcurOld);
}