home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
07
/
pcx_cpp.asc
< prev
next >
Wrap
Text File
|
1991-06-11
|
36KB
|
1,108 lines
_A C++ PCX FILE VIEWER FOR WINDOWS 3_
by Paul Chui
[LISTING ONE]
#include <windows.h>
#include "pcxwin.h"
#include <io.h>
#define ALIGN_DWORD(x) (((x)+3)/4 * 4)
struct PCXRGB { BYTE r, g, b; };
struct PCXHEADER {
BYTE pcxManufacturer;
BYTE pcxVersion;
BYTE pcxEncoding;
BYTE pcxBitsPixel;
int pcxXmin, pcxYmin;
int pcxXmax, pcxYmax;
int pcxHres, pcxVres;
PCXRGB pcxPalette[16];
BYTE pcxReserved;
BYTE pcxPlanes;
int pcxBytesLine;
int pcxPaletteInfo;
BYTE pcxFiller[58];
};
///////////////////////////////////////////////////////////////////////////
// NOTES: Decoder creates a DIB and possibly a PALETTE, but does not delete
// either. It is the responsibility of the Decoder's user to delete them.
///////////////////////////////////////////////////////////////////////////
class DecodePCX {
public:
DecodePCX(int hfile, PCXHEADER& pcxHeader);
virtual HBITMAP MakeDIB(HDC hdc) = 0;
HPALETTE Palette();
protected:
WORD read_pcx_line(BYTE huge* pLine);
BOOL NEAR PASCAL next_data();
int hFile; // Handle to the open PCX file
HPALETTE hPalette; // Handle to Palette
PCXHEADER header;
int BytesLine; // Bytes/Line in PCX file
WORD width; // width in pixels
WORD height; // height in scan lines
BYTE byData; // Current data byte
int iDataBytes; // Current unread data buffer size
};
HPALETTE DecodePCX::Palette() { return hPalette; }
class DecodeMonoPCX : public DecodePCX {
public:
DecodeMonoPCX(int hfile, PCXHEADER& pcxHeader) :
DecodePCX(hfile, pcxHeader) { }
HBITMAP MakeDIB(HDC hdc);
};
class Decode16PCX: public DecodePCX {
public:
Decode16PCX(int hfile, PCXHEADER& pcxHeader) :
DecodePCX(hfile, pcxHeader) { }
HBITMAP MakeDIB(HDC hdc);
};
class Decode256PCX: public DecodePCX {
public:
Decode256PCX(int hfile, PCXHEADER& pcxHeader) :
DecodePCX(hfile, pcxHeader) { }
HBITMAP MakeDIB(HDC hdc);
private:
HPALETTE make_palette(RGBQUAD* pColors);
};
///////////////////////////////////////////////////////////////////////////
// PCX Methods
///////////////////////////////////////////////////////////////////////////
PCX::PCX()
{
hBitmap = 0;
hPalette = 0;
hFile = 0;
wWidth = 0;
wHeight = 0;
}
PCX::~PCX()
{
if (hBitmap) DeleteObject(hBitmap);
if (hPalette) DeleteObject(hPalette);
}
/****************************************************************************
METHOD: BOOL PCX::Read(LPSTR lpszFileName, HDC hdc)
PURPOSE: Creates a DIB from a PCX file
PARAMETERS: LPSTR lpszFileName PCX file name
HDC hdc A compatible DC for the DIB
RETURN: TRUE if DIB was created, otherwise FALSE
NOTES: ZSoft documents a CGA palette type that is not support here.
****************************************************************************/
BOOL PCX::Read(LPSTR lpszFileName, HDC hdc)
{
// Delete the bitmap and reset variables
if (hBitmap)
{
DeleteObject(hBitmap);
hBitmap = 0; // So we know the bitmap has been deleted
}
if (hPalette)
{
DeleteObject(hPalette);
hPalette = 0; // So we know the palette has been deleted
}
wWidth = 0;
wHeight = 0;
OFSTRUCT OfStruct;
if ((hFile=OpenFile(lpszFileName, &OfStruct, OF_READ)) == -1)
{
ErrorMessage("Unable to open file.");
return FALSE;
}
PCXHEADER header;
if (_lread(hFile,(LPSTR)&header,sizeof(PCXHEADER)) != sizeof(PCXHEADER))
{
ErrorMessage("Error reading PCX file header.");
return FALSE;
}
if(header.pcxManufacturer != 0x0a)
{
_lclose(hFile);
ErrorMessage("Not a PCX file.");
return FALSE;
}
wWidth = header.pcxXmax - header.pcxXmin + 1;
wHeight = header.pcxYmax - header.pcxYmin + 1;
DecodePCX* Decoder;
/* Determine PCX file type and create a decoder */
// 256-color file
if (header.pcxBitsPixel == 8 && header.pcxPlanes == 1)
Decoder = new Decode256PCX(hFile, header);
else
// 16-color file
if (header.pcxBitsPixel == 1 && header.pcxPlanes == 4)
Decoder = new Decode16PCX(hFile, header);
else
// monochrome file
if (header.pcxBitsPixel == 1 && header.pcxPlanes == 1)
Decoder = new DecodeMonoPCX(hFile, header);
else
ErrorMessage("Unsupported PCX format.");
if (!Decoder)
{
ErrorMessage("Cannot create PCX decoder.");
_lclose(hFile);
return FALSE;
}
SetCursor( LoadCursor(NULL,IDC_WAIT) );
// Create the bitmap
hBitmap = Decoder->MakeDIB(hdc);
hPalette = Decoder->Palette();
SetCursor( LoadCursor(NULL,IDC_ARROW) );
delete Decoder;
_lclose(hFile);
return (hBitmap) ? TRUE : FALSE;
}
/****************************************************************************
METHOD: BOOL PCX::Display(HDC hdc, POINT& pos, RECT& rect)
PURPOSE: Displays the DIB
PARAMETERS: HDC hdc DC on which DIB is displayed
POINT pos Destination positions
RECT rect Clipping rectangle on source
RETURN: TRUE if DIB was displayed, otherwise FALSE
NOTES: Works for MM_TEXT mode only
****************************************************************************/
BOOL PCX::Display(HDC hdc, POINT& pos, RECT& rect)
{
BOOL bltOk = FALSE;
if (hBitmap)
{
HBITMAP hdcBitmap = CreateCompatibleDC(hdc);
HBITMAP hOldBitmap = SelectObject(hdcBitmap, hBitmap);
bltOk = BitBlt(hdc, rect.left,rect.top,rect.right,rect.bottom,
hdcBitmap,pos.x,pos.y, SRCCOPY);
SelectObject(hdcBitmap, hOldBitmap);
DeleteDC(hdcBitmap);
}
return bltOk;
}
///////////////////////////////////////////////////////////////////////////
// DecodePCX Methods
///////////////////////////////////////////////////////////////////////////
/****************************************************************************
METHOD: DecodePCX::DecodePCX(int hfile, PCXHEADER& pcxHeader)
PURPOSE: Constructor
PARAMETERS: int hfile Handle to open PCX file
PCXHEADER pcxHeader PCX header
****************************************************************************/
DecodePCX::DecodePCX(int hfile, PCXHEADER& pcxHeader)
{
hFile = hfile;
// Reset file pointer
if (_llseek(hFile, sizeof(PCXHEADER), 0) == -1)
ErrorMessage("Error positioning past header.");
header = pcxHeader;
hPalette = 0;
BytesLine = header.pcxBytesLine;
width = header.pcxXmax - header.pcxXmin + 1;
height = header.pcxYmax - header.pcxYmin + 1;
byData = 0;
iDataBytes = 0;
}
/****************************************************************************
METHOD: WORD DecodePCX::read_pcx_line(BYTE huge* lpLineImage)
PURPOSE: Decode a PCX RLE scanline
PARAMETERS: BYTE huge* lpLineImage Destination of decoded scanline
RETURN: Number of bytes decoded
****************************************************************************/
WORD DecodePCX::read_pcx_line(BYTE huge* lpLineImage)
{
for (WORD n=0; n<BytesLine; )
{
if (!next_data()) return n;
// If the two high bits are set...
if (byData >= 0xc0)
{
// Get duplication count from lower bits
BYTE run_len = byData & 0x3f;
// Set run_len bytes
if (!next_data()) return n;
while(run_len--) lpLineImage[n++]=byData;
}
else
// Set this byte
lpLineImage[n++] = byData;
}
if (n != BytesLine)
ErrorMessage("PCX Read Error.");
return n;
}
/****************************************************************************
METHOD: BOOL NEAR PASCAL DecodePCX::next_data()
PURPOSE: Read a byte from the file and set to byData
RETURN: FALSE on read error
NOTES: The output byte is written to byData
****************************************************************************/
BOOL NEAR PASCAL DecodePCX::next_data()
{
static BYTE fileBuf[5120];
static int index = 0;
if (iDataBytes == 0)
{
if ((iDataBytes = _read(hFile, fileBuf, sizeof(fileBuf))) <= 0)
return FALSE;
index = 0;
}
--iDataBytes;
byData = *(fileBuf+(index++));
return TRUE;
}
///////////////////////////////////////////////////////////////////////////
// DecodeMonoPCX Methods
///////////////////////////////////////////////////////////////////////////
/****************************************************************************
METHOD: HBITMAP DecodeMonoPCX::MakeDIB(HDC hdc)
PURPOSE: Make monochrome DIB
PARAMETERS: HDC hdc Handle to compatible DC
RETURNS: Handle to DIB, NULL on error
****************************************************************************/
HBITMAP DecodeMonoPCX::MakeDIB(HDC hdc)
{
int h;
LONG lDIBBytesLine = ALIGN_DWORD(BytesLine);
LONG image_size = lDIBBytesLine*height;
// Allocate memory for the image buffer
GlobalCompact(image_size);
HANDLE hImageMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, image_size);
if (!hImageMem)
{
ErrorMessage("Out of memory."); return NULL;
}
BYTE huge* lpImage = (BYTE huge*) GlobalLock(hImageMem);
if (!lpImage)
{
ErrorMessage("Memory error."); return NULL;
}
for (h=height-1; h>=0; --h)
read_pcx_line(lpImage+(lDIBBytesLine*h));
// Create the DIB header
PBITMAPINFO pBmi = (PBITMAPINFO)
new BYTE[ sizeof(BITMAPINFOHEADER)+2*sizeof(RGBQUAD) ];
if (!pBmi)
{
ErrorMessage("Out of memory.");
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return NULL;
}
PBITMAPINFOHEADER pBi = &pBmi->bmiHeader;
pBi->biSize = sizeof(BITMAPINFOHEADER);
pBi->biWidth = width;
pBi->biHeight = height;
pBi->biPlanes = 1;
pBi->biBitCount = 1;
pBi->biCompression = 0L;
pBi->biSizeImage = 0L;
pBi->biXPelsPerMeter = 0L;
pBi->biYPelsPerMeter = 0L;
pBi->biClrUsed = 0L;
pBi->biClrImportant = 0L;
// Copy PCX Palette into DIB color table
pBmi->bmiColors[0].rgbBlue = header.pcxPalette[0].b;
pBmi->bmiColors[0].rgbGreen = header.pcxPalette[0].g;
pBmi->bmiColors[0].rgbRed = header.pcxPalette[0].r;
pBmi->bmiColors[1].rgbBlue = header.pcxPalette[1].b;
pBmi->bmiColors[1].rgbGreen = header.pcxPalette[1].g;
pBmi->bmiColors[1].rgbRed = header.pcxPalette[1].r;
HBITMAP hBitmap = CreateDIBitmap(hdc, pBi, CBM_INIT,
(LPSTR)lpImage, pBmi, DIB_RGB_COLORS);
delete pBmi;
// Free image buffer
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return hBitmap;
}
///////////////////////////////////////////////////////////////////////////
// Decode16PCX Methods
///////////////////////////////////////////////////////////////////////////
/****************************************************************************
METHOD: HBITMAP Decode16PCX::MakeDIB(HDC hdc)
PURPOSE: Make 16-color DIB
PARAMETERS: HDC hdc Handle to compatible DC
RETURNS: Handle to DIB, NULL on error
****************************************************************************/
HBITMAP Decode16PCX::MakeDIB(HDC hdc)
{
LONG lDIBBytesLine = ALIGN_DWORD( (width+1)/2 );
LONG image_size = lDIBBytesLine*height;
// Allocate memory for the image buffer
GlobalCompact(image_size);
HANDLE hImageMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, image_size);
if (!hImageMem)
{
ErrorMessage("Out of memory."); return NULL;
}
BYTE huge* lpImage = (BYTE huge*) GlobalLock(hImageMem);
if (!lpImage)
{
ErrorMessage("Memory error."); return NULL;
}
// 16 color PCX files interleve scanlines for each color
BYTE *npPlane[4];
for (int h=0; h<4; ++h)
npPlane[h] = new BYTE[BytesLine];
if (!npPlane[0] || !npPlane[1] || !npPlane[2] || !npPlane[3])
{
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return NULL;
}
// 16 color DIB bitmaps have 4 bits per pixel
for (h=height-1; h>=0; --h)
{
read_pcx_line(npPlane[0]);
read_pcx_line(npPlane[1]);
read_pcx_line(npPlane[2]);
read_pcx_line(npPlane[3]);
LONG l = (LONG) h * lDIBBytesLine;
for (int m=0; m<BytesLine; ++m)
{
BYTE r = npPlane[0][m];
BYTE g = npPlane[1][m];
BYTE b = npPlane[2][m];
BYTE i = npPlane[3][m];
// Combine a bit from each 4 scan lines into a 4-bit nibble
BYTE nibbles = 0;
for (int k=0; k<4; ++k)
{
nibbles = 0;
// If the most significant bit is set...
// Set the appropriate bit in the higher order nibble
if (r & '\x80') nibbles |= 0x10;
if (g & '\x80') nibbles |= 0x20;
if (b & '\x80') nibbles |= 0x40;
if (i & '\x80') nibbles |= 0x80;
r<<=1; g<<=1; b<<=1; i<<=1;
// Repeat for the lower order nibble
if (r & '\x80') nibbles |= 0x01;
if (g & '\x80') nibbles |= 0x02;
if (b & '\x80') nibbles |= 0x04;
if (i & '\x80') nibbles |= 0x08;
r<<=1; g<<=1; b<<=1; i<<=1;
*(lpImage + l++) = nibbles;
}
}
}
for (h=0; h<4; ++h)
delete npPlane[h];
// Create the DIB header
PBITMAPINFO pBmi = (PBITMAPINFO)
new BYTE[ sizeof(BITMAPINFOHEADER)+16*sizeof(RGBQUAD) ];
if (!pBmi)
{
ErrorMessage("Out of memory.");
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return NULL;
}
PBITMAPINFOHEADER pBi = &pBmi->bmiHeader;
pBi->biSize = sizeof(BITMAPINFOHEADER);
pBi->biWidth = width;
pBi->biHeight = height;
pBi->biPlanes = 1;
pBi->biBitCount = 4;
pBi->biCompression = 0L;
pBi->biSizeImage = 0L;
pBi->biXPelsPerMeter = 0L;
pBi->biYPelsPerMeter = 0L;
pBi->biClrUsed = 0L;
pBi->biClrImportant = 0L;
if (header.pcxVersion == 3)
// No PCX palette, use literal color values
{
DWORD* clrTab = (DWORD*)pBmi->bmiColors;
clrTab[0] = 0x000000L;
clrTab[1] = 0x000080L;
clrTab[2] = 0x008000L;
clrTab[3] = 0x008080L;
clrTab[4] = 0x800000L;
clrTab[5] = 0x800080L;
clrTab[6] = 0x808000L;
clrTab[7] = 0x808080L;
clrTab[8] = 0xc0c0c0L;
clrTab[9] = 0x0000ffL;
clrTab[10] = 0x00ff00L;
clrTab[11] = 0x00ffffL;
clrTab[12] = 0xff0000L;
clrTab[13] = 0xff00ffL;
clrTab[14] = 0xffff00L;
clrTab[15] = 0xffffffL;
}
else
// Copy PCX palette to DIB color table
{
for (int i=0; i<16; ++i)
{
pBmi->bmiColors[i].rgbBlue = header.pcxPalette[i].b;
pBmi->bmiColors[i].rgbGreen = header.pcxPalette[i].g;
pBmi->bmiColors[i].rgbRed = header.pcxPalette[i].r;
pBmi->bmiColors[i].rgbReserved = 0;
}
}
HBITMAP hBitmap = CreateDIBitmap(hdc, pBi, CBM_INIT,
(LPSTR)lpImage, pBmi, DIB_RGB_COLORS);
delete pBmi;
// Free image buffer
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return hBitmap;
}
///////////////////////////////////////////////////////////////////////////
// Decode256PCX Methods
///////////////////////////////////////////////////////////////////////////
/****************************************************************************
METHOD: HBITMAP Decode256PCX::MakeDIB(HDC hdc)
PURPOSE: Make 256-color DIB
PARAMETERS: HDC hdc Handle to compatible DC
RETURNS: Handle to DIB, NULL on error
****************************************************************************/
HANDLE Decode256PCX::MakeDIB(HDC hdc)
{
LONG lDIBBytesLine = ALIGN_DWORD(BytesLine);
LONG image_size = lDIBBytesLine*height;
// Allocate memory for the image buffer
GlobalCompact(image_size);
HANDLE hImageMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, image_size);
if (!hImageMem)
{
ErrorMessage("Out of memory."); return NULL;
}
BYTE huge* lpImage = (BYTE huge*) GlobalLock(hImageMem);
if (!lpImage)
{
ErrorMessage("Memory error."); return NULL;
}
for (int h=height-1; h>=0; --h)
read_pcx_line(lpImage+(lDIBBytesLine*h));
// Create the DIB header
PBITMAPINFO pBmi = (PBITMAPINFO)
new BYTE[ sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD) ];
if (!pBmi)
{
ErrorMessage("Out of memory.");
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return NULL;
}
PBITMAPINFOHEADER pBi = &pBmi->bmiHeader;
pBi->biSize = sizeof(BITMAPINFOHEADER);
pBi->biWidth = width;
pBi->biHeight = height;
pBi->biPlanes = 1;
pBi->biBitCount = 8;
pBi->biCompression = 0L;
pBi->biSizeImage = 0L;
pBi->biXPelsPerMeter = 0L;
pBi->biYPelsPerMeter = 0L;
pBi->biClrUsed = 0L;
pBi->biClrImportant = 0L;
// Look for the palette at the end of the file
if (_llseek(hFile, -769L, 2) == -1)
ErrorMessage("Error seeking palette.");
// It should start with a 0Ch byte
BYTE Id256Pal;
if (!(_read(hFile, &Id256Pal, 1) == 1 && Id256Pal == '\xc'))
ErrorMessage("No palette found.");
PCXRGB* PalPCX = new PCXRGB[256];
if (_read(hFile, PalPCX, 768) != 768)
ErrorMessage("Error reading palette.");
// Copy PCX palette to DIB color table
for (int i=0; i<256; ++i)
{
pBmi->bmiColors[i].rgbBlue = PalPCX[i].b;
pBmi->bmiColors[i].rgbGreen = PalPCX[i].g;
pBmi->bmiColors[i].rgbRed = PalPCX[i].r;
pBmi->bmiColors[i].rgbReserved = 0;
}
delete PalPCX;
if (hPalette)
DeleteObject(hPalette);
// Create and set logical palette
if ((hPalette = make_palette(pBmi->bmiColors)) != NULL)
{
SelectPalette(hdc, hPalette, 0);
RealizePalette(hdc);
}
else
{
ErrorMessage("Cannot create palette");
}
HBITMAP hBitmap = CreateDIBitmap(hdc, pBi, CBM_INIT,
(LPSTR)lpImage, pBmi, DIB_RGB_COLORS);
delete pBmi;
// Free image buffer
GlobalUnlock(hImageMem);
GlobalFree(hImageMem);
return hBitmap;
}
/****************************************************************************
METHOD: HPALETTE Decode256PCX::make_palette(RGBQUAD* pColors)
PURPOSE: Make 256-color Logical Palette
PARAMETERS: RGBQUAD[256] pColors Palette colors
RETURNS: Handle to Palette, NULL on error
****************************************************************************/
HPALETTE Decode256PCX::make_palette(RGBQUAD* pColors)
{
if (!pColors)
return NULL;
PLOGPALETTE pPal = (PLOGPALETTE)
new BYTE[ sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
if (!pPal)
return NULL;
pPal->palNumEntries = 256;
pPal->palVersion = 0x300;
for (int i=0; i<256; ++i)
{
pPal->palPalEntry[i].peRed = pColors[i].rgbRed;
pPal->palPalEntry[i].peGreen = pColors[i].rgbGreen;
pPal->palPalEntry[i].peBlue = pColors[i].rgbBlue;
pPal->palPalEntry[i].peFlags = 0;
}
HPALETTE hPal = CreatePalette(pPal);
delete pPal;
return hPal;
}
[LISTING TWO]
#include <windows.h>
#include "pcxwin.h"
#include <stdlib.h>
static char szAppName[] = "PCXWIN";
#define MAXPATH 80
static char szFileName[MAXPATH+1] = "";
static char szUntitled[] = "PCXWIN - (Untitled)";
// Function Prototypes
int DoKeyDown(HWND hwnd, WORD wVkey);
int DoFileOpenDlg(HANDLE hInst, HWND hwnd);
LONG FAR PASCAL _export WndProc(HWND hwnd, WORD message,
WORD wParam, LONG lParam);
BOOL FAR PASCAL _export FileOpenDlgProc(HWND hDlg, WORD message,
WORD wParam, LONG lParam);
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR, int nCmdShow)
{
if (!hPrevInstance)
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, "PCXWIN");
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = "PCXWIN";
wndclass.lpszClassName = szAppName;
RegisterClass(&wndclass);
}
HWND hwnd = CreateWindow(
szAppName, szUntitled,
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL
);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
HANDLE hAccel = LoadAccelerators(hInstance, szAppName);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LONG FAR PASCAL _export WndProc(HWND hwnd, WORD message,
WORD wParam, LONG lParam)
{
static HANDLE hInst;
static PCX* pcx;
static Scroller* scroll;
HDC hdc;
switch(message)
{
case WM_CREATE :
hInst = ((LPCREATESTRUCT) lParam)->hInstance;
pcx = new PCX;
scroll = new Scroller(hwnd);
return 0L;
case WM_DESTROY :
delete pcx;
delete scroll;
PostQuitMessage(0);
return 0L;
case WM_PAINT :
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
RECT rcClient;
GetClientRect(hwnd, &rcClient);
pcx->Display(hdc, scroll->Pos(), rcClient);
EndPaint(hwnd, &ps);
return 0L;
case WM_QUERYNEWPALETTE:
if (pcx->Palette())
{
hdc = GetDC(hwnd);
SelectPalette(hdc, pcx->Palette(), 0);
BOOL b = RealizePalette(hdc);
ReleaseDC(hwnd, hdc);
if (b)
{
InvalidateRect(hwnd, NULL, 1);
return 1L;
}
}
return 0L;
case WM_SIZE :
scroll->Size(pcx->Size());
return 0L;
case WM_VSCROLL :
scroll->Vert(wParam, LOWORD(lParam));
return 0L;
case WM_HSCROLL :
scroll->Horz(wParam, LOWORD(lParam));
return 0L;
case WM_KEYDOWN :
return DoKeyDown(hwnd, wParam);
case WM_COMMAND :
switch (wParam)
{
case IDM_OPEN :
if (DoFileOpenDlg(hInst, hwnd))
{
hdc = GetDC(hwnd);
if (pcx->Read(szFileName, hdc))
{
char wtext[70];
wsprintf(wtext, "PcxWin - %.40s (%u x %u)",
AnsiUpper(szFileName),pcx->Width(), pcx->Height());
SetWindowText(hwnd, wtext);
}
else
{
SetWindowText(hwnd, szUntitled);
}
ReleaseDC(hwnd, hdc);
POINT ptNewPos = {0,0};
scroll->Pos(ptNewPos);
scroll->Size(pcx->Size());
}
InvalidateRect(hwnd, NULL, TRUE);
break;
case IDM_ABOUT:
MessageBox(hwnd, "PCXWIN (c) Paul Chui, 1991",
"About PCXWIN...", MB_OK | MB_ICONINFORMATION);
break;
case IDM_EXIT :
DestroyWindow(hwnd);
break;
case IDM_COPY :
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_BITMAP, pcx->Bitmap());
CloseClipboard();
}
return 0L;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int DoKeyDown(HWND hwnd, WORD wVkey)
{
switch (wVkey)
{
case VK_HOME : SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0L); break;
case VK_END : SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0L); break;
case VK_PRIOR : SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0L); break;
case VK_NEXT : SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L); break;
case VK_UP : SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0L); break;
case VK_DOWN : SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0L); break;
case VK_LEFT : SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0L); break;
case VK_RIGHT : SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0L); break;
}
return 0;
}
BOOL DoFileOpenDlg(HANDLE hInst, HWND hwnd)
{
FARPROC lpfnFileOpenDlgProc = MakeProcInstance((FARPROC)FileOpenDlgProc,
hInst);
BOOL bReturn = DialogBox(hInst, "FileOpen", hwnd, lpfnFileOpenDlgProc);
FreeProcInstance(lpfnFileOpenDlgProc);
return bReturn;
}
BOOL FAR PASCAL FileOpenDlgProc(HWND hDlg, WORD message, WORD wParam, LONG)
{
switch(message)
{
case WM_INITDIALOG :
SendDlgItemMessage(hDlg, IDD_FNAME, EM_LIMITTEXT, MAXPATH, 0L);
SetDlgItemText(hDlg, IDD_FNAME, szFileName);
return TRUE;
case WM_COMMAND :
switch(wParam)
{
case IDOK :
GetDlgItemText(hDlg, IDD_FNAME, szFileName, MAXPATH);
EndDialog(hDlg, TRUE);
return TRUE;
case IDCANCEL :
szFileName[0] = '\0'; // erase the string
EndDialog(hDlg, FALSE);
return TRUE;
}
}
return FALSE;
}
[LISTING THREE]
#ifndef PCXWIN_H
#define PCXWIN_H
#define IDM_OPEN 0x10
#define IDM_EXIT 0x11
#define IDM_ABOUT 0x12
#define IDM_COPY 0x20
#define IDD_FNAME 0x20
class PCX {
public:
PCX();
~PCX();
virtual BOOL Read(LPSTR lpszFileName, HDC theHdc);
virtual BOOL Display(HDC hdc, POINT& pos, RECT& rect);
POINT Size();
WORD Width();
WORD Height();
HBITMAP Bitmap();
HPALETTE Palette();
private:
WORD wWidth, wHeight;
HBITMAP hBitmap;
HPALETTE hPalette;
int hFile; // Input file handle
};
inline POINT PCX::Size() { POINT p = {wWidth,wHeight}; return p; }
inline WORD PCX::Width() { return wWidth; }
inline WORD PCX::Height() { return wHeight; }
inline HBITMAP PCX::Bitmap() { return hBitmap; }
inline HPALETTE PCX::Palette() { return hPalette; }
class Scroller {
public:
Scroller(HWND hwnd);
int Size(POINT& ptImgSize);
int Vert(WORD wSBcode, WORD wSBPos);
int Horz(WORD wSBcode, WORD wSBPos);
POINT Pos();
POINT Pos(POINT& ptNewPos);
private:
HWND hClientWnd;
POINT ptPos; // Current Scroll position
POINT ptMax; // Max Scroll range
POINT ptInc; // Scroll increment
POINT ptClient; // Size of client window
};
inline POINT Scroller::Pos() { return ptPos; }
inline POINT Scroller::Pos(POINT& ptNewPos) { return ptPos = ptNewPos; }
inline void ErrorMessage(PSTR message)
{
MessageBox(NULL, (LPSTR) message, (LPSTR) "Error", MB_OK|MB_ICONEXCLAMATION);
}
/* The standard max and min macros are undefined by BC++ because
they may conflict with class-defined macros with the same names. */
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
[LISTING FOUR]
#include <windows.h>
#include "pcxwin.h"
//////////////////////// Class Scroller ////////////////////////////////
Scroller::Scroller(HWND hwnd)
{
ptPos.x = 0; ptPos.y = 0;
ptMax.x = 0; ptMax.y = 0;
ptInc.x = 0; ptInc.y = 0;
RECT rect;
GetClientRect(hwnd, &rect);
ptClient.x = rect.right; ptClient.y = rect.bottom;
hClientWnd = hwnd;
}
int Scroller::Size(POINT& ptImgSize)
{
RECT rect;
GetClientRect(hClientWnd, &rect);
ptClient.x = rect.right; ptClient.y = rect.bottom;
ptMax.x = MAX(0, ptImgSize.x - ptClient.x);
ptPos.x = MIN(ptPos.x, ptMax.x);
SetScrollRange(hClientWnd, SB_HORZ, 0, ptMax.x, FALSE);
SetScrollPos(hClientWnd, SB_HORZ, ptPos.x, TRUE);
ptMax.y = MAX(0, ptImgSize.y - ptClient.y);
ptPos.y = MIN(ptPos.y, ptMax.y);
SetScrollRange(hClientWnd, SB_VERT, 0, ptMax.y, FALSE);
SetScrollPos(hClientWnd, SB_VERT, ptPos.y, TRUE);
return 0;
}
int Scroller::Vert(WORD wSBcode, WORD wSBPos)
{
switch (wSBcode)
{
case SB_LINEUP :
ptInc.y = -1;
break;
case SB_LINEDOWN :
ptInc.y = 1;
break;
case SB_PAGEUP :
ptInc.y = MIN(-1, -ptClient.y/4);
break;
case SB_PAGEDOWN :
ptInc.y = MAX(1, ptClient.y/4);
break;
case SB_TOP :
ptInc.y = -ptInc.y;
break;
case SB_BOTTOM :
ptInc.y = ptMax.y - ptPos.y;
break;
case SB_THUMBPOSITION :
ptInc.y = wSBPos - ptPos.y;
break;
default :
ptInc.y = 0;
}
if (( ptInc.y = MAX(-ptPos.y, MIN(ptInc.y, ptMax.y - ptPos.y)) ) != 0)
{
ptPos.y += ptInc.y;
ScrollWindow(hClientWnd, 0, -ptInc.y, NULL, NULL);
SetScrollPos(hClientWnd, SB_VERT, ptPos.y, TRUE);
UpdateWindow(hClientWnd);
}
return 0;
}
int Scroller::Horz(WORD wSBcode, WORD wSBPos)
{
switch (wSBcode)
{
case SB_LINEUP :
ptInc.x = -1;
break;
case SB_LINEDOWN :
ptInc.x = 1;
break;
case SB_PAGEUP :
ptInc.x = MIN(-1, -ptClient.x/4);
break;
case SB_PAGEDOWN :
ptInc.x = MAX(1, ptClient.x/4);
break;
case SB_THUMBPOSITION :
ptInc.x = wSBPos - ptPos.x;
break;
default :
ptInc.x = 0;
}
if (( ptInc.x = MAX(-ptPos.x, MIN(ptInc.x, ptMax.x - ptPos.x)) ) != 0)
{
ptPos.x += ptInc.x;
ScrollWindow(hClientWnd, -ptInc.x, 0, NULL, NULL);
SetScrollPos(hClientWnd, SB_HORZ, ptPos.x, TRUE);
UpdateWindow(hClientWnd);
}
return 0;
}
[LISTING FIVE]
NAME PCXWIN
DESCRIPTION 'PCX Viewer (c) Paul Chui, 1991'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVABLE MULTIPLE
HEAPSIZE 1046
STACKSIZE 8192
PROTMODE
[LISTING SIX]
#include <windows.h>
#include "pcxwin.h"
PCXWin MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open" IDM_OPEN
MENUITEM SEPARATOR
MENUITEM "E&xit" IDM_EXIT
MENUITEM "A&bout PCXWIN..." IDM_ABOUT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Copy\tCtrl+Ins" IDM_COPY
END
END
FILEOPEN DIALOG DISCARDABLE LOADONCALL PURE MOVEABLE 10, 35, 129, 56
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | 0x80L
CAPTION "Open File"
BEGIN
CONTROL "File &name:" -1, "STATIC", WS_CHILD | WS_VISIBLE, 8, 7, 56, 12
CONTROL "" IDD_FNAME, "EDIT", WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_TABSTOP | 0x80L, 7, 15, 116, 12
CONTROL "OK" IDOK, "BUTTON", WS_CHILD | WS_VISIBLE |
WS_TABSTOP, 15, 36, 40, 12
CONTROL "Cancel" IDCANCEL, "BUTTON", WS_CHILD | WS_VISIBLE |
WS_TABSTOP, 69, 36, 40, 12
END
PCXWin ACCELERATORS
{
VK_INSERT, IDM_COPY, VIRTKEY, CONTROL
}
[LISTING SEVEN]
.AUTODEPEND
# *Translator Definitions*
CC = bccx +PCXWIN.CFG
TASM = TASM
TLINK = tlink
# *Implicit Rules*
.c.obj:
$(CC) -c {$< }
.cpp.obj:
$(CC) -c {$< }
# *List Macros*
Link_Exclude = \
pcxwin.res
Link_Include = \
pcxwin.obj \
showpcx.obj \
scroller.obj \
pcxwin.def
# *Explicit Rules*
pcxwin.exe: pcxwin.cfg $(Link_Include) $(Link_Exclude)
$(TLINK) /v/x/n/c/Twe/P-/LC:\CPP\LIB @&&|
c0ws.obj+
pcxwin.obj+
showpcx.obj+
scroller.obj
pcxwin
# no map file
cwins.lib+
import.lib+
maths.lib+
cs.lib
pcxwin.def
|
RC -T pcxwin.res pcxwin.exe
# *Individual File Dependencies*
pcxwin.obj: pcxwin.cpp
showpcx.obj: showpcx.cpp
scroller.obj: scroller.cpp
pcxwin.res: pcxwin.rc
RC -R -IC:\CPP\INCLUDE -FO pcxwin.res PCXWIN.RC
# *Compiler Configuration File*
pcxwin.cfg: pcxwin.mak
copy &&|
-v
-W
-H=PCXWIN.SYM
-IC:\CPP\INCLUDE
-LC:\CPP\LIB
| pcxwin.cfg
Example 1:
BYTE huge* lpImage = new BYTE[lImageSize];
int h, line, plane;
for (h=0, line=0; h<wHeight; ++h, line+=byPlanes)
for (plane=0; plane<byPlanes; ++plane)
read_pcx_line(lpImage+(lBmpBytesLine*(line+plane)));
HBITMAP hBitmap = CreateBitmap(wWidth, wHeight, byPlanes, 1, lpImage);
Example 2:
BYTE huge* lpImage = new BYTE[lImageSize];
int h, line, plane;
if (lImageSize < 65535L)
// Interlaced color scanlines
for (h=0, line=0; h<wHeight; ++h, line+=byPlanes)
for (plane=0; plane<byPlanes; ++plane)
read_pcx_line(lpImage+(LONG(iBmpBytesLine)*(line+plane)));
else
// Interlaced color planes
for (h=0, line=0; h<wHeight; ++h, line+=wHeight)
for (plane=0; plane<byPlanes; ++plane)
read_pcx_line(lpImage+(lBmpBytesLine*(plane*wHeight+h)));
HBITMAP hBitmap = CreateBitmap(wWidth, wHeight, byPlanes, 1, lpImage);