/*************************************************************************** * * * MODULE : ICClip.C * * * * DESCRIPTION : Clipboard functions for ImagEdit * * * * FUNCTIONS : CopyImageClip () - Copies selected portion of image to * * the clipboard. * * * * PasteImageClip () - Pastes the clipboard image to * * selected portion of edit image. * * * * * * HISTORY : 6/21/89 - created by LR * * * ***************************************************************************/ #include "imagedit.h" #include "dialogs.h" #include "iehelp.h" #include /*========================================================================== |ImagEdit's clipboard data is in two formats: | | a) a standard CF_BITMAP format and | | b) a private ImagEdit format described below. | | | |The private ImagEdit format data consists of: | | 1. a DWORD describing screen color when image was sent to clipboard | | followed by... | | 2. the DIB bits of the monochrome AND image (in ghdcANDMask). | | | |The CF_BITMAP format consists of the image bitmap (the combined XOR and | |AND images in ghdcImage for icons and cursors). | | | |This information is sufficient to re-create the image correctly during | |paste even if the screen viewing color is subsequently changed. | | | |Both formats are created if the image being edited is an icon or a cursor.| |Only the CF_BITMAP format is created if a bitmap is being edited. | ==========================================================================*/ /**************************************************************************** * * * FUNCTION : BOOL PASCAL CopyImageClip(fBitmap) * * * * PURPOSE : Copies the information from the selected area of image to * * the clipboard. * * * * SIDE EFFECTS: may change contents of the clipboard. The "pick" or clip * * rectangle is reset to cover the entire image. * * * ****************************************************************************/ BOOL CopyImageClip(VOID) { HCURSOR hcurOld; HBITMAP hStdBitmap; HBITMAP hPrivBitmap; HDC hStdDC; HDC hPrivDC; HANDLE hOldSObj; HANDLE hOldPObj; HANDLE hPriv; LPSTR lpPriv; hcurOld = SetCursor(hcurWait); /* create a temp. bitmap and DC for the standard clipboard format * along the same lines as the image bitmap */ hStdDC = CreateCompatibleDC(ghdcImage); hStdBitmap = MyCreateBitmap(ghdcImage, gcxPick, gcyPick, 16); hOldSObj = SelectObject(hStdDC, hStdBitmap); /* blt the image bits into standard format DC */ BitBlt(hStdDC, 0, 0, gcxPick, gcyPick, ghdcImage, grcPick.left, grcPick.top, SRCCOPY); SelectObject(hStdDC, hOldSObj); if (giType != FT_BITMAP) { /* for icons and cursors, create a temp. DC and bitmap for the AND * mask and blt the mask bits into it. */ hPrivDC = CreateCompatibleDC(ghdcANDMask); hPrivBitmap = CreateCompatibleBitmap(ghdcANDMask, gcxPick, gcyPick); hOldPObj = SelectObject(hPrivDC, hPrivBitmap); BitBlt(hPrivDC, 0, 0, gcxPick, gcyPick, ghdcANDMask, grcPick.left, grcPick.top, SRCCOPY); /* Allocate a buffer for the private ImagEdit format */ hPriv = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)((gcxPick + 31) >> 3) * gcyPick + sizeof(DWORD)); if (!hPriv) { DeleteDC(hStdDC); DeleteObject(hStdBitmap); DeleteDC(hPrivDC); DeleteObject(hPrivBitmap); return FALSE; } lpPriv = (LPSTR)GlobalLock(hPriv); /* Fill in the first DWORD with the screen color information */ *((DWORD FAR *)lpPriv) = grgbScreen; /* Get the mask bits into the buffer */ GetBitmapBits(hPrivBitmap, (DWORD)((gcxPick + 31) >> 3) * gcyPick, (LPSTR)lpPriv + sizeof(DWORD)); SelectObject(hPrivDC, hOldPObj); DeleteObject(hPrivBitmap); DeleteDC(hPrivDC); } /* Open clipboard and clear it of it's contents */ if (!OpenClipboard(ghwndMain)) { DeleteDC(hStdDC); return(FALSE); } EmptyClipboard(); if (giType != FT_BITMAP) { /* set the private ImagEdit format data into the clipboard */ if (!SetClipboardData(ClipboardFormat, hPriv)) { DeleteDC(hStdDC); GlobalUnlock(hPriv); GlobalFree(hPriv); CloseClipboard(); return(FALSE); } GlobalUnlock(hPriv); } /* set the standard CF_BITMAP format data in the clipboard */ if (!SetClipboardData(CF_BITMAP, hStdBitmap)) { DeleteDC(hStdDC); GlobalFree(hPriv); // hPriv may not have been initialized (if giType == BITMAP). CloseClipboard(); return(FALSE); } CloseClipboard(); DeleteDC(hStdDC); /* * Reset pick rectangle to cover entire image. */ PickSetRect(0, 0, gcxImage - 1, gcyImage - 1); /* * Erase the drag rectangle. */ WorkUpdate(); SetCursor(hcurOld); return TRUE; } /************************************************************************ * PasteImageClip * * Pastes an image from the clipboard to the current image. * * It is assumed that this routine will not be called unless an * image is currently being edited. * * The pick rectangle is reset to cover the entire image if the * paste is successful. * * Basic outline of how Paste is done in ImagEdit. * * Find out what format is available in the clipboard: * a. CF_BITMAP only * -------------- * case 1: Pasting to an icon or cursor * * We don't have any screen color information. * Make the mask bits opaque and blt. the bitmap to * ghdcImage. * * case 2: Pasting to a bitmap * * Blt the bitmap to the image DC. * * b. both ImagEdit and CF_BITMAP * --------------------------- * case 1: Pasting to an icon or cursor * * Recover the image from the AND and screen color * data (in ImagEdit) and the combined image bitmap * (in CF_BITMAP). Use the information to make the * neccessary changes if the screen viewing color was * changed between Copy and Paste. * * case 2: Pasting to a bitmap * * Blt the CF_BITMAP data to the image DC. * * If the destination image differs in dimensions from * source image, the source image is stretched or clipped to that of * destination, depending on preference * * History: * ************************************************************************/ BOOL PasteImageClip(VOID) { HCURSOR hcurOld; INT cxClip; INT cyClip; INT cxTarget; INT cyTarget; INT cxSource; INT cySource; DWORD rgbClipScreen; BOOL fIEFormatFound; HANDLE hClipData; LPSTR lpClipData; BITMAP bmClip; HDC hdcClip; HBITMAP hbmClip; HBITMAP hbmClipOld; HDC hdcClipAND; HBITMAP hbmClipAND; HBITMAP hbmClipANDOld; HDC hdcClipAND16; HBITMAP hbmClipAND16; HBITMAP hbmClipAND16Old; HDC hdcTarget; HBITMAP hbmTarget; HBITMAP hbmTargetOld; HDC hdcTargetAND16; HBITMAP hbmTargetAND16; HBITMAP hbmTargetAND16Old; HDC hdcTargetAND; HBITMAP hbmTargetAND; HBITMAP hbmTargetANDOld; hcurOld = SetCursor(hcurWait); if (!OpenClipboard(ghwndMain)) { Message(MSG_NOCLIPBOARD); goto Error1; } if (!(hbmClip = GetClipboardData(CF_BITMAP))) { Message(MSG_NOCLIPBOARDFORMAT); goto Error2; } GetObject(hbmClip, sizeof(BITMAP), (LPSTR)&bmClip); cxClip = (INT)bmClip.bmWidth; cyClip = (INT)bmClip.bmHeight; /* * If the dimensions of the current pick rectangle don't match * the bitmap being pasted, ask the user if they want to stretch * or clip the pasted image. */ cxTarget = gcxPick; cyTarget = gcyPick; cxSource = cxClip; cySource = cyClip; if (gcxPick != cxClip || gcyPick != cyClip) { if (DlgBox(DID_PASTEOPTIONS, (WNDPROC)PasteOptionsDlgProc) == IDCANCEL) { goto Error2; } /* * If clipping and the clipboard dimensions differ from the * selected pick rectangle, then either the target dimensions * or the source dimensions need to be sized down. */ if (!fStretchClipboardData) { if (cxClip < gcxPick) cxTarget = cxClip; else cxSource = gcxPick; if (cyClip < gcyPick) cyTarget = cyClip; else cySource = gcyPick; } } /* * Update the undo buffer now that we are committed to the paste. */ ImageUpdateUndo(); /* * Determine if the private ImagEdit clipboard format is available. */ fIEFormatFound = IsClipboardFormatAvailable(ClipboardFormat); if (giType != FT_BITMAP && fIEFormatFound) { /* * Get the AND mask bitmap and the old screen color out of * the private format. */ hClipData = GetClipboardData(ClipboardFormat); lpClipData = (LPSTR)GlobalLock(hClipData); rgbClipScreen = *((DWORD FAR *)lpClipData); hdcClipAND = CreateCompatibleDC(ghdcImage); hbmClipAND = CreateBitmap(cxClip, cyClip, (BYTE)1, (BYTE)1, (LPSTR)lpClipData + sizeof(DWORD)); hbmClipANDOld = SelectObject(hdcClipAND, hbmClipAND); /* * Create a color bitmap for temporary use. */ hdcClipAND16 = CreateCompatibleDC(ghdcImage); hbmClipAND16 = MyCreateBitmap(ghdcImage, cxSource, cySource, 16); hbmClipAND16Old = SelectObject(hdcClipAND16, hbmClipAND16); /* * Blt the AND mask onto the color bitmap. */ BitBlt(hdcClipAND16, 0, 0, cxSource, cySource, hdcClipAND, 0, 0, SRCCOPY); /* * Create the color target AND mask bitmap. */ hdcTargetAND16 = CreateCompatibleDC(ghdcImage); hbmTargetAND16 = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 16); hbmTargetAND16Old = SelectObject(hdcTargetAND16, hbmTargetAND16); /* * StretchBlt from the color AND mask bitmap to the color target * AND mask bitmap. The blt must be done from a color bitmap to * a color bitmap, and the stretch blt mode must be set to * COLORONCOLOR. All this is necessary so that the AND mask * stays exactly in sync with the stretch blt of the color * (XOR) mask. If these steps are not done correctly, shrinking * an image with screen colored pixels in it can cause problems, * because the stretch blt will use a slightly different * algorithm to compress the monochrome AND mask and the color * XOR mask. */ SetStretchBltMode(hdcTargetAND16, COLORONCOLOR); SetStretchBltMode(hdcClipAND16, COLORONCOLOR); // StretchBlt(hdcTargetAND16, 0, 0, cxTarget, cyTarget, hdcClipAND16, 0, 0, cxSource, cySource, SRCCOPY); /* * Create the monochrome target AND mask bitmap. */ hdcTargetAND = CreateCompatibleDC(ghdcImage); hbmTargetAND = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 2); hbmTargetANDOld = SelectObject(hdcTargetAND, hbmTargetAND); /* * Blt the color AND mask onto the monochrome AND mask. * The monochrome AND mask is the one that we will use * later. It must be monochrome or the ImageDCSeparate * and ImageDCCombine functions will not work properly. */ BitBlt(hdcTargetAND, 0, 0, cxTarget, cyTarget, hdcTargetAND16, 0, 0, SRCCOPY); /* * Cleanup. */ SelectObject(hdcTargetAND16, hbmTargetAND16Old); DeleteObject(hbmTargetAND16); DeleteDC(hdcTargetAND16); SelectObject(hdcClipAND16, hbmClipAND16Old); DeleteObject(hbmClipAND16); DeleteDC(hdcClipAND16); SelectObject(hdcClipAND, hbmClipANDOld); DeleteObject(hbmClipAND); DeleteDC(hdcClipAND); GlobalUnlock(hClipData); } /* * Get the clipboard bitmap into a DC. */ hdcClip = CreateCompatibleDC(ghdcImage); hbmClipOld = SelectObject(hdcClip, hbmClip); /* * Create the target bitmap. */ hdcTarget = CreateCompatibleDC(ghdcImage); hbmTarget = MyCreateBitmap(ghdcImage, cxTarget, cyTarget, 16); hbmTargetOld = SelectObject(hdcTarget, hbmTarget); /* * StretchBlt the bitmap onto the target. */ SetStretchBltMode(hdcTarget, COLORONCOLOR); SetStretchBltMode(hdcClip, COLORONCOLOR); // StretchBlt(hdcTarget, 0, 0, cxTarget, cyTarget, hdcClip, 0, 0, cxSource, cySource, SRCCOPY); /* * Handle some special cases. */ if (giType == FT_BITMAP || !fIEFormatFound) { /* * The image we are pasting into is either a bitmap, or * there does not exist an AND mask in the clipboard. */ if (gnColors == 2) { /* * We are pasting to a mono image. We must convert the * colors in the clipboard bitmap into monochrome. */ ImageDCMonoBlt(hdcTarget, cxTarget, cyTarget); } } else { /* * We are pasting into an icon or cursor image and we have * available an AND mask. Is the current image monochrome? */ if (gnColors == 2) { /* * Remove the old screen/inverse colors from the image, * convert it to monochrome, then put back in the * current screen/inverse colors. */ ImageDCSeparate(hdcTarget, cxTarget, cyTarget, hdcTargetAND, rgbClipScreen); ImageDCMonoBlt(hdcTarget, cxTarget, cyTarget); ImageDCCombine(hdcTarget, cxTarget, cyTarget, hdcTargetAND); } /* * Does the screen color specified in the clipboard * differ from the current screen color? */ else if (rgbClipScreen != grgbScreen) { /* * Remove the old screen/inverse colors, then put back * in the current ones. */ ImageDCSeparate(hdcTarget, cxTarget, cyTarget, hdcTargetAND, rgbClipScreen); ImageDCCombine(hdcTarget, cxTarget, cyTarget, hdcTargetAND); } } /* * Blt the clipboard image to the proper rectangle in the current image. */ BitBlt(ghdcImage, grcPick.left, grcPick.top, cxTarget, cyTarget, hdcTarget, 0, 0, SRCCOPY); /* * If the current image is an icon or cursor, we must take care * of the AND mask also. */ if (giType != FT_BITMAP) { /* * Is there an AND mask in the clipboard to use? */ if (fIEFormatFound) { /* * Blt it into the current image's AND mask. */ BitBlt(ghdcANDMask, grcPick.left, grcPick.top, cxTarget, cyTarget, hdcTargetAND, 0, 0, SRCCOPY); } else { /* * Make the AND mask opaque, because there is no * screen color information. */ PatBlt(ghdcANDMask, grcPick.left, grcPick.top, cxTarget, cyTarget, BLACKNESS); } } /* * Cleanup. */ SelectObject(hdcTarget, hbmTargetOld); DeleteObject(hbmTarget); DeleteDC(hdcTarget); if (giType != FT_BITMAP && fIEFormatFound) { SelectObject(hdcTargetAND, hbmTargetANDOld); DeleteObject(hbmTargetAND); DeleteDC(hdcTargetAND); } SelectObject(hdcClip, hbmClipOld); DeleteDC(hdcClip); CloseClipboard(); /* * Update the View and workspace windows. */ ViewUpdate(); /* * Reset pick rectangle to cover entire image. */ PickSetRect(0, 0, gcxImage - 1, gcyImage - 1); fImageDirty = TRUE; SetCursor(hcurOld); return TRUE; Error2: CloseClipboard(); Error1: SetCursor(hcurOld); return FALSE; } /************************************************************************ * PasteOptionsDlgProc * * Proc for the dialog that asks the user whether they want to clip * or stretch the bitmap being pasted in. * * Upon return with an IDOK value, the fStretchClipboardData global * will be TRUE if they want to stretch, or FALSE if they want to clip. * * History: * ************************************************************************/ DIALOGPROC PasteOptionsDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: CheckRadioButton(hwnd, DID_PASTEOPTIONSSTRETCH, DID_PASTEOPTIONSCLIP, fStretchClipboardData ? DID_PASTEOPTIONSSTRETCH : DID_PASTEOPTIONSCLIP); CenterWindow(hwnd); break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK : if (IsDlgButtonChecked(hwnd, DID_PASTEOPTIONSSTRETCH)) fStretchClipboardData = TRUE; else fStretchClipboardData = FALSE; EndDialog(hwnd, IDOK); break; case IDCANCEL: EndDialog(hwnd, IDCANCEL); break; case IDHELP: WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT, HELPID_PASTEOPTIONS); break; } break; default: return FALSE; } return TRUE; } /************************************************************************ * PickSetRect * * Sets the globals for the picking rectangle size. This affects * what is copied into the clipboard. * * Arguments: * * History: * ************************************************************************/ VOID PickSetRect( INT xLeft, INT yTop, INT xRight, INT yBottom) { SetRect(&grcPick, xLeft, yTop, xRight, yBottom); gcxPick = (grcPick.right - grcPick.left) + 1; gcyPick = (grcPick.bottom - grcPick.top) + 1; }