home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Graphics
/
Graphics.zip
/
gotch175.zip
/
src
/
savebmp.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2002-12-16
|
21KB
|
652 lines
/***
This file belongs to the Gotcha! distribution.
Copyright (C) 1998-2002 Thorsten Thielen <thth@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***/
// ** SaveBitmap ********************************************************** /*FOLD00*/
VOID SaveBitmap (HBITMAP hbm, HPS hps)
{
#ifdef _DOLOGMEM_
LogMem("SaveBitmap", TRUE);
#endif
if( pset->QueryFileSaveStyle () == FSS_FORCEFILE )
{
PSZ psz = pset->QueryForceSaveFile();
psz = AddExtensionToFilename( psz );
SaveBitmapToFile( hbm, psz, hps );
#ifdef _DOLOGMEM_
LogMem( "SaveBitmap-1", FALSE );
#endif
return;
}
if (pset->DoSound ())
{
DosBeep ( 500, 100);
DosBeep (1000, 100);
DosBeep (1500, 100);
}
switch (pset->QuerySaveStyle ())
{
case SAVESTYLE_CLIPBOARD:
SaveBitmapToClipboard (hbm);
break;
default:
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmap()" );
#endif
if (SelectSaveFile ()) {
#ifdef _DOLOGDEBUG_
LogDebug( "Before call to SaveBitmapToFile()" );
#endif
SaveBitmapToFile (hbm, pset->QuerySaveFile (), hps);
#ifdef _DOLOGDEBUG_
LogDebug( "After call to SaveBitmapToFile()" );
#endif
}
break;
}
#ifdef _DOLOGMEM_
LogMem("SaveBitmap-2", FALSE);
#endif
}
// ** SaveBitmapToClipboard *********************************************** /*FOLD00*/
VOID SaveBitmapToClipboard (HBITMAP hbm)
{
#ifdef _DOLOGMEM_
LogMem("SaveBitmapToClipboard", TRUE);
#endif
// copy the thing to the clipboard
WinOpenClipbrd (hab);
WinEmptyClipbrd (hab);
WinSetClipbrdData (hab, ULONG (hbm), CF_BITMAP, CFI_HANDLE);
WinCloseClipbrd (hab);
#ifdef _DOLOGMEM_
LogMem("SaveBitmapToClipboard", FALSE);
#endif
}
// ** SaveBitmapToFile **************************************************** /*FOLD00*/
#define CB_12HEADER sizeof (BITMAPINFOHEADER) // == 12
#define CB_16HEADER (sizeof (BITMAPINFOHEADER2)-24)
#define CB_20HEADER sizeof (BITMAPINFOHEADER2) // == 64
VOID SaveBitmapToFile (HBITMAP hbm, PSZ psz, HPS hps)
{
ULONG rc;
#ifdef _DOLOGMEM_
LogMem("SaveBitmapToFile", TRUE);
#endif
#ifdef _DOLOGDEBUG_
LogDebug( "Start of SaveBitmapToFile()" );
#endif
// get the fullsized bitmap info header from the bitmap
BITMAPINFOHEADER2 bih2;
bih2.cbFix = sizeof (BITMAPINFOHEADER2);
if (! GpiQueryBitmapInfoHeader (hbm, &bih2))
{
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Exit GpiQueryBitmapInfoHeader" );
#endif
DisplayError (RSTR(IDS_HEADER_ERROR),
RSTR(IDS_ERROR_COULDNOTRETRIEVEHEADER),
WinGetLastError (hab));
return;
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): GpiQueryBitmapInfoHeader ok." );
#endif
// get the size of the colortable
ULONG cbColtab = 0L, cColors = 0L;
if (bih2.cBitCount == 8)
cColors = 256L;
else if (bih2.cBitCount == 4)
cColors = 16L;
else if (bih2.cBitCount == 1)
cColors = 2L;
cbColtab = cColors * sizeof( RGB2 );
// get size of bits buffer and allocate it
ULONG cbBits =
(bih2.cBitCount * bih2.cx + 31L)/32L * bih2.cPlanes * 4L * bih2.cy;
PBYTE pb =
PBYTE (malloc (cbBits));
// allocate and init the file info header
PBITMAPFILEHEADER2 pbfh2 =
PBITMAPFILEHEADER2 (malloc (sizeof (BITMAPFILEHEADER2)+cbColtab));
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Filling header." );
#endif
// fill the bitmap header with the bitmap data
memcpy (&(pbfh2->bmp2), &bih2, sizeof (BITMAPINFOHEADER2));
pbfh2->bmp2.cbImage = cbBits;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before GpiQueryBitmapBits." );
#endif
// grab the bits!! ;-) - and the colortable
if (GpiQueryBitmapBits (hps, 0, bih2.cy, pb, PBITMAPINFO2 (&(pbfh2->bmp2)))
== GPI_ALTERROR)
{
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Exit GpiQueryBitmapBits" );
#endif
DisplayError (RSTR(IDS_HEADER_ERROR),
RSTR(IDS_ERROR_COULDNOTGETBITMAPBITS),
WinGetLastError (hab));
free (pb);
return;
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): GpiQueryBitmapBits ok." );
#endif
pbfh2->usType = BFT_BMAP;
pbfh2->offBits = sizeof (BITMAPFILEHEADER2)-sizeof (BITMAPINFOHEADER2);
switch (pset->QueryFileFormat ())
{
case BMF_12:
pbfh2->offBits += CB_12HEADER + cColors*sizeof (RGB);
break;
case BMF_20:
pbfh2->offBits += CB_20HEADER + cColors*sizeof (RGB2);
break;
default:
pbfh2->offBits += CB_16HEADER + cColors*sizeof (RGB2);
break;
}
pbfh2->cbSize = pbfh2->offBits+cbBits;
pbfh2->xHotspot = pbfh2->yHotspot = 0;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before if." );
#endif
if( ( pset->QueryFileFormat() == BMF_12 ) ||
( pset->QueryFileFormat() == BMF_16 ) ||
( pset->QueryFileFormat() == BMF_20 ) )
{
// open out file
FILE *pf = fopen (psz, "wb");
if (! pf)
{
DisplayError (RSTR(IDS_HEADER_ERROR), RSTR(IDS_ERROR_COULDNOTOPENFILE),
psz);
free (pb);
return;
}
// write file info header
fwrite (pbfh2, sizeof (BITMAPFILEHEADER2)-sizeof (BITMAPINFOHEADER2),
1, pf);
// write bitmap info header
switch (pset->QueryFileFormat ())
{
case BMF_12:
{
BITMAPINFOHEADER bih;
bih.cbFix = CB_12HEADER;
bih.cx = USHORT (bih2.cx);
bih.cy = USHORT (bih2.cy);
bih.cPlanes = bih2.cPlanes;
bih.cBitCount = bih2.cBitCount;
fwrite (&bih, CB_12HEADER, 1, pf);
}
break;
case BMF_20:
pbfh2->bmp2.cbFix = CB_20HEADER;
fwrite (&(pbfh2->bmp2), CB_20HEADER, 1, pf);
break;
default:
pbfh2->bmp2.cbFix = CB_16HEADER;
fwrite (&(pbfh2->bmp2), CB_16HEADER, 1, pf);
break;
}
// write colortable if present
if (cbColtab)
{
switch (pset->QueryFileFormat ())
{
case BMF_12:
{
RGB rgb;
for (USHORT i = 0; i < cColors; i++)
{
rgb.bRed = PBITMAPINFO2 (&(pbfh2->bmp2))
->argbColor[i].bRed;
rgb.bGreen = PBITMAPINFO2 (&(pbfh2->bmp2))
->argbColor[i].bGreen;
rgb.bBlue = PBITMAPINFO2 (&(pbfh2->bmp2))
->argbColor[i].bBlue;
fwrite (&rgb, sizeof (rgb), 1, pf);
}
}
break;
default:
fwrite (PBYTE (&(pbfh2->bmp2))+sizeof (BITMAPINFOHEADER2),
cbColtab, 1, pf);
break;
}
}
// write the actual bitmap data bits
fwrite (pb, cbBits, 1, pf);
fclose (pf);
} else {
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Starting 'else' path." );
#endif
PFN xmmioClose = pset->GetMMIO()->pfmmioClose;
PFN xmmioOpen = pset->GetMMIO()->pfmmioOpen;
PFN xmmioWrite = pset->GetMMIO()->pfmmioWrite;
PFN xmmioQueryHeaderLength = pset->GetMMIO()->pfmmioQueryHeaderLength;
PFN xmmioSetHeader = pset->GetMMIO()->pfmmioSetHeader;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before GetFOURCC." );
#endif
// ********* WRITE TARGET
FOURCC fccTargetIOProc = pset->GetFOURCC();
// Initialize our info MMIOINFO structure.
MMIOINFO mmioinfoTarget;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before memset." );
#endif
memset( &mmioinfoTarget, 0L, sizeof( MMIOINFO ) );
mmioinfoTarget.fccIOProc = fccTargetIOProc;
mmioinfoTarget.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Trying to open file." );
#endif
// Open target file.
HMMIO hmmioTarget;
if( ! ( hmmioTarget = pset->GetMMIO()->pfmmioOpen( psz,
&mmioinfoTarget,
MMIO_CREATE | MMIO_WRITE |
MMIO_DENYWRITE | MMIO_NOIDENTIFY ) ) ) {
DisplayError ("mmioOpen()-Error",
"mmioOpen()-Error %ld", mmioinfoTarget.ulErrorRet );
return;
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Open file ok." );
#endif
// Set the target header.
ULONG ulImageHeaderLength;
xmmioQueryHeaderLength( hmmioTarget, (PLONG)&ulImageHeaderLength, 0L, 0L );
if( ulImageHeaderLength != sizeof( MMIMAGEHEADER ) )
{
// We have a problem.....possibly incompatible versions.
xmmioClose( hmmioTarget, 0L );
DisplayError ("mmioQueryHeaderLength()-Error",
"mmioQueryHeaderLength()-Error",
WinGetLastError (hab));
return;
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): xmmioQueryHeaderLength ok." );
#endif
MMIMAGEHEADER mmImgHdr;
mmImgHdr.ulHeaderLength = ulImageHeaderLength;
mmImgHdr.ulContentType = MMIO_IMAGE_UNKNOWN;
mmImgHdr.ulMediaType = MMIO_MEDIATYPE_IMAGE;
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before memcpy (colors)." );
#endif
memcpy( mmImgHdr.bmiColors,
PBYTE( &( pbfh2->bmp2 ) ) + sizeof( BITMAPINFOHEADER2 ),
cbColtab );
mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulMemSize = cbBits; // FIXME;
mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulPelFormat = 0; // FIXME;
mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.usTransType = 0; // FIXME
mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulTransVal = 0; // FIXME
memcpy( &(mmImgHdr.mmXDIBHeader.BMPInfoHeader2), &bih2, sizeof (BITMAPINFOHEADER2));
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Before xmmioSetHeader." );
#endif
ULONG ulBytesRead;
if( ( rc = (LONG)xmmioSetHeader( hmmioTarget, (MMIMAGEHEADER*)&mmImgHdr,
(LONG)sizeof( MMIMAGEHEADER ), (PLONG)&ulBytesRead,
0L, 0L ) ) != MMIO_SUCCESS )
{
// Header unavailable.
xmmioClose( hmmioTarget, 0L );
DisplayError ("mmioSetHeader()-Error",
"mmioSetHeader()-Error %ld", rc );
return;
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): xmmioSetHeader ok." );
#endif
// write the actual bitmap data bits
if( ( rc = xmmioWrite( hmmioTarget, pb, cbBits ) ) == MMIO_ERROR )
DisplayError ("mmioWrite()-Error",
"mmioWrite()-Error %ld", rc );
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): xmmioWrite ok." );
#endif
if( ( rc = xmmioClose( hmmioTarget, 0 ) ) != MMIO_SUCCESS )
DisplayError ("mmioClose()-Error",
"mmioClose()-Error %ld", rc );
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): xmmioClose ok." );
#endif
}
#ifdef _DOLOGDEBUG_
LogDebug( "SaveBitmapToFile(): Everything done, closed file" );
#endif
// set BITMAP file type ea
SetEAs( psz );
// cleanup and return
free (pbfh2);
free (pb);
#ifdef _DOLOGMEM_
LogMem("SaveBitmapToFile", FALSE);
#endif
}
// ** SetEAs ************************************************************** /*fold00*/
BOOL SetEAs (PSZ psz)
{
#ifdef _DOLOGMEM_
LogMem("SetEAs", TRUE);
#endif
// alloc memory for EA data
PSZ pszName = ".TYPE";
PSZ pszValue = pset->GetFileEAType();
USHORT cbName = strlen (pszName)+1;
USHORT cbValue = strlen (pszValue)+1;
USHORT usMemNeeded = sizeof (FEA2LIST) + cbName + cbValue;
PBYTE pb = PBYTE (malloc (usMemNeeded));
EAOP2 eaop2;
eaop2.fpFEA2List = (FEA2LIST FAR *) pb;
eaop2.fpFEA2List->cbList = usMemNeeded;
eaop2.fpFEA2List->list[0].fEA = 0; // EA is no "must have"
eaop2.fpFEA2List->list[0].cbName = cbName-1;
eaop2.fpFEA2List->list[0].cbValue = cbValue;
strcpy (eaop2.fpFEA2List->list[0].szName, pszName);
memcpy (eaop2.fpFEA2List->list[0].szName+cbName, pszValue, cbValue);
if (DosSetPathInfo (psz, FIL_QUERYEASIZE, PVOID (&eaop2),
sizeof (EAOP2), DSPI_WRTTHRU))
{
DisplayError (RSTR(IDS_HEADER_ERROR),
RSTR(IDS_ERROR_COULDNOTWRITEFILETYPEEA));
free (pb);
#ifdef _DOLOGMEM_
LogMem("SetEAs-1", FALSE);
#endif
return FALSE;
}
free (pb);
#ifdef _DOLOGMEM_
LogMem("SetEAs-2", FALSE);
#endif
return TRUE;
}
// ** SelectSaveFile ****************************************************** /*fold00*/
BOOL SelectSaveFile (VOID)
{
#ifdef _DOLOGMEM_
LogMem("SelectSaveFile", TRUE);
#endif
// if FSS_NUMFILES, create and return a new name
if (pset->QueryFileSaveStyle () == FSS_NUMFILES)
{
CHAR ach[_MAX_PATH];
for (USHORT i = 0; i < 10000; i++)
{
sprintf( ach, "%s\\got%05d.%s", pset->QueryNumSaveDir(), i,
pset->GetFileExtension() );
if (access (ach, 0) != 0)
{
pset->SetSaveFile (ach);
return TRUE;
}
}
return FALSE;
}
// ... else do a file dlg
FILEDLG fdlg;
memset (&fdlg, 0, sizeof (fdlg));
fdlg.hMod = GETMODULE;
fdlg.usDlgId = ID_DLG_FILE;
fdlg.pfnDlgProc = FileDLGProcedure;
fdlg.cbSize = sizeof (fdlg);
fdlg.fl = FDS_SAVEAS_DIALOG | FDS_CENTER | FDS_CUSTOM;
fdlg.pszTitle = RSTR(IDS_SAVESCREENSHOTTO);
strcpy (fdlg.szFullFile, pset->QuerySaveFile ());
if (WinFileDlg (HWND_DESKTOP, HWND_DESKTOP, &fdlg))
{
if (fdlg.lReturn != DID_OK)
return FALSE;
PSZ pszOut = fdlg.szFullFile;
// Add bmp extension if not already present.
if( pset->AutoaddExtension() )
pszOut = AddExtensionToFilename( pszOut );
// if file exists and user wants it, confirm overwriting
if (pset->ConfirmOverwrite ())
if (access (pszOut, 0) == 0)
// let user confirm operation
if (WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
RSTR(IDS_FILEEXISTSOVERWRITE),
RSTR(IDS_HEADER_WARNING), 0L,
MB_OKCANCEL | MB_QUERY | MB_DEFBUTTON2 |
MB_MOVEABLE)
!= MBID_OK)
return FALSE;
pset->SetSaveFile (pszOut);
return TRUE;
}
return FALSE;
#ifdef _DOLOGMEM_
LogMem("SelectSaveFile", FALSE);
#endif
}
// ** FileDLGProcedure **************************************************** /*fold00*/
MRESULT EXPENTRY FileDLGProcedure (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
#ifdef _DOFNCOMPLETION_
static HDIR hdir = NULLHANDLE;
static BOOL fCompletion = FALSE;
#endif
switch (msg)
{
case WM_INITDLG:
WinSendDlgItemMsg (hwnd, WID_CB_AUTOADDEXTENSION, BM_SETCHECK,
MPFROMLONG (pset->AutoaddExtension ()),
MPFROMLONG (0));
WinSendDlgItemMsg (hwnd, WID_CB_CONFIRMOVERWRITE, BM_SETCHECK,
MPFROMLONG (pset->ConfirmOverwrite ()),
MPFROMLONG (0));
/* FIXME neither work ... WinSendDlgItemMsg (hwnd, DID_FILES_LB, WM_ENABLE,
MPFROMLONG (TRUE),
MPFROMLONG (0));
//WinEnableWindow( WinWindowFromID( hwnd, DID_FILES_LB ), TRUE ); */
break;
#ifdef _DOFNCOMPLETION_
case WM_CHAR: {
HWND hwndFNE = WinWindowFromID (hwnd, DID_FILENAME_ED);
if (WinQueryFocus (HWND_DESKTOP) == hwndFNE)
{
// tab key, downpress
if ((CHARMSG (&msg)->chr == 9) && !
(CHARMSG (&msg)->fs & KC_KEYUP))
{
ULONG c = 1, fl;
FILEFINDBUF3 findbuf;
APIRET rc;
CHAR ach[_MAX_PATH];
if (! hdir)
{
WinQueryWindowText (hwndFNE, _MAX_PATH-1, ach);
strcat (ach, "*");
fl = FILE_NORMAL;
hdir = HDIR_CREATE;
rc = DosFindFirst (ach, &hdir, fl, &findbuf,
sizeof (findbuf), &c,
FIL_STANDARD);
}
else
{
rc = DosFindNext (hdir, &findbuf,
sizeof (findbuf), &c);
}
if (! rc)
{
fCompletion = TRUE;
WinSetWindowText (hwndFNE, findbuf.achName);
fCompletion = FALSE;
}
else
DosBeep (1000, 10);
return MRESULT (FALSE);
}
} } break;
case WM_CONTROL:
switch (SHORT1FROMMP (mp1))
{
case DID_FILENAME_ED:
if ((SHORT2FROMMP (mp1) == EN_CHANGE) ||
(SHORT2FROMMP (mp1) == EN_KILLFOCUS))
if (hdir && !fCompletion)
{
// FIXME maybe do this to when closing dialog?
DosFindClose (hdir);
hdir = NULLHANDLE;
}
break;
}
break;
#endif
case WM_COMMAND:
case WM_CLOSE:
pset->AutoaddExtension
(BOOL (WinSendDlgItemMsg (hwnd, WID_CB_AUTOADDEXTENSION,
BM_QUERYCHECK, 0, 0)));
pset->ConfirmOverwrite
(BOOL (WinSendDlgItemMsg (hwnd, WID_CB_CONFIRMOVERWRITE,
BM_QUERYCHECK, 0, 0)));
break;
}
return WinDefFileDlgProc (hwnd, msg, mp1, mp2);
}
// ** AddExtensionToFilename ********************************************** /*fold00*/
PSZ AddExtensionToFilename( PSZ psz )
{
// Using a static buffer here is not really good, but good enough
// currently as we know there will be no concurrent access.
static CHAR ach[_MAX_PATH];
PSZ pszExtension;
PSZ apszValidExtensions[10] =
{ "bmp", "tif", "tiff", "tga", "targa", "pcx", "gif", "jpg", "jpeg", "dib" };
if( ! ( pszExtension = strrchr( psz, '.' ) ) ) {
// No extension at all - add the appropriate one.
sprintf( ach, "%s.%s", psz, pset->GetFileExtension() );
} else if( stricmp ( pszExtension+1, pset->GetFileExtension() ) == 0 ) {
// Correct extension already - just return unchanged filename.
strcpy( ach, psz );
} else {
// Some extension, but not the correct one - change or append.
BOOL fValidExtension = FALSE;
for( int i = 0; i < 10; i++ ) {
if( stricmp( pszExtension+1, apszValidExtensions[i] ) == 0 ) {
fValidExtension = TRUE;
break;
}
}
if( fValidExtension ) {
// Valid extension, but not right for current format - replace.
*pszExtension = '\0';
sprintf( ach, "%s.%s", psz, pset->GetFileExtension() );
} else {
// Some extension but not a valid image file format extension - add.
sprintf( ach, "%s.%s", psz, pset->GetFileExtension() );
}
}
return ach;
}
// ************************************************************************