home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-06-11 | 35.4 KB | 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);
-
-
-
-
-