X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/56c667557e4df2f4da14c3ef90e80e9fa3cb3ffe..f76dbc4d52c005b63745cf924efe30eece4c6f79:/src/common/imagpcx.cpp diff --git a/src/common/imagpcx.cpp b/src/common/imagpcx.cpp index f31797bdad..73bee7edf3 100644 --- a/src/common/imagpcx.cpp +++ b/src/common/imagpcx.cpp @@ -3,8 +3,8 @@ // Purpose: wxImage PCX handler // Author: Guillermo Rodriguez Garcia // Version: 1.00 -// Last rev: 1999/08/24 -// Copyright: (c) Guillermo Rodriguez Garcia +// CVS-ID: $Id$ +// Copyright: (c) 1999 Guillermo Rodriguez Garcia // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -20,11 +20,200 @@ #pragma hdrstop #endif +#ifndef WX_PRECOMP +# include "wx/defs.h" +#endif + +#if wxUSE_STREAMS && wxUSE_PCX + #include "wx/image.h" #include "wx/wfstream.h" #include "wx/module.h" #include "wx/log.h" + +//----------------------------------------------------------------------------- +// PCX decoding +//----------------------------------------------------------------------------- + +void RLEencode(unsigned char *WXUNUSED(p), unsigned int WXUNUSED(size), wxOutputStream& WXUNUSED(s)) +{ +} + +void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) +{ + unsigned int i, data, cont; + + // Read 'size' bytes. The PCX official specs say there will be + // a decoding break at the end of each scanline (but not at the + // end of each plane inside a scanline). Only use this function + // to read one or more _complete_ scanlines. Else, more than + // 'size' bytes might be read and the buffer might overflow. + // + while (size > 0) + { + data = (unsigned char)s.GetC(); + + // If ((data & 0xC0) != 0xC0), then the value read is a data + // byte. Else, it is a counter (cont = val & 0x3F) and the + // next byte is the data byte. + // + if ((data & 0xC0) != 0xC0) + { + *(p++) = data; + size--; + } + else + { + cont = data & 0x3F; + data = (unsigned char)s.GetC(); + for (i = 1; i <= cont; i++) + *(p++) = data; + size -= cont; + } + } +} + + +/* PCX header */ +#define HDR_VERSION 1 +#define HDR_ENCODING 2 +#define HDR_BITSPERPIXEL 3 +#define HDR_XMIN 4 +#define HDR_YMIN 6 +#define HDR_XMAX 8 +#define HDR_YMAX 10 +#define HDR_NPLANES 65 +#define HDR_BYTESPERLINE 66 + +/* image formats */ +#define IMAGE_8BIT 0 // 8 bpp, 1 plane (8 bit) +#define IMAGE_24BIT 1 // 8 bpp, 3 planes (24 bit) + +/* error codes */ +#define E_OK 0 // everything was OK +#define E_FORMATO 1 // error in pcx file format +#define E_MEMORIA 2 // error allocating memory +#define E_VERSION 3 // error in pcx version number + + +// ReadPCX: +// Loads a PCX file into the wxImage object pointed by image. +// Returns E_OK on success, or an error code otherwise (see +// above for error codes) +// +int ReadPCX(wxImage *image, wxInputStream& stream) +{ + unsigned char hdr[128]; // PCX header + unsigned char pal[768]; // palette for 8 bit images + unsigned char *p; // space to store one scanline + unsigned char *dst; // pointer into wxImage data + unsigned int width, height; // size of the image + unsigned int bytesperline; // bytes per line (each plane) + int bitsperpixel; // bits per pixel (each plane) + int nplanes; // number of planes + int encoding; // is the image RLE encoded? + int format; // image format (8 bit, 24 bit) + unsigned int i; + off_t pos; + + // Read PCX header and check the version number (it must + // be at least 5 or higher for 8 bit and 24 bit images). + // + stream.Read(hdr, 128); + + if (hdr[HDR_VERSION] < 5) return E_VERSION; + + // Extract all image info from the PCX header. + // + encoding = hdr[HDR_ENCODING]; + nplanes = hdr[HDR_NPLANES]; + bitsperpixel = hdr[HDR_BITSPERPIXEL]; + bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; + width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - + (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; + height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - + (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; + + // Check image format. Currently supported formats are + // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). + // + if ((nplanes == 3) && (bitsperpixel == 8)) + format = IMAGE_24BIT; + else if ((nplanes == 1) && (bitsperpixel == 8)) + format = IMAGE_8BIT; + else + return E_FORMATO; + + // If the image is of type IMAGE_8BIT, then there is a + // palette at the end of the file. Read it now before + // proceeding. + // + if (format == IMAGE_8BIT) + { + pos = stream.TellI(); + stream.SeekI(-769, wxFromEnd); + + if (stream.GetC() != 12) + return E_FORMATO; + + stream.Read(pal, 768); + stream.SeekI(pos, wxFromStart); + } + + // Allocate memory for a scanline and resize the image. + // + image->Create(width, height); + + if (!image->Ok()) + return E_MEMORIA; + + if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) + return E_MEMORIA; + + // Now start reading the file, line by line, and store + // the data in the format required by wxImage. + // + dst = image->GetData(); + + for (; height; height--) + { + if (encoding) + RLEdecode(p, bytesperline * nplanes, stream); + else + stream.Read(p, bytesperline * nplanes); + + switch (format) + { + case IMAGE_8BIT: + { + for (i = 0; i < width; i++) + { + *(dst++) = pal[ 3 * (p[i]) ]; + *(dst++) = pal[ 3 * (p[i]) + 1]; + *(dst++) = pal[ 3 * (p[i]) + 2]; + } + break; + } + case IMAGE_24BIT: + { + for (i = 0; i < width; i++) + { + *(dst++) = p[i]; + *(dst++) = p[i + bytesperline]; + *(dst++) = p[i + 2 * bytesperline]; + } + break; + } + } + } + + free(p); + + return E_OK; +} + + //----------------------------------------------------------------------------- // wxPCXHandler //----------------------------------------------------------------------------- @@ -33,32 +222,60 @@ IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) #endif -#if wxUSE_STREAMS - bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose ) { + int error; + + if (!CanRead(stream)) + { + if (verbose) + wxLogError(wxT("wxPCXHandler: this is not a PCX file")); + + return FALSE; + } + image->Destroy(); - if (verbose) - wxLogDebug(_T("wxPCXHandler::LoadFile still not implemented")); + if ((error = ReadPCX(image, stream)) != E_OK) + { + if (verbose) + { + switch (error) + { + case E_FORMATO: wxLogError(wxT("wxPCXHandler: image format unsupported")); break; + case E_MEMORIA: wxLogError(wxT("wxPCXHandler: couldn't allocate memory")); break; + case E_VERSION: wxLogError(wxT("wxPCXHandler: version number too low")); break; + default: wxLogError(wxT("wxPCXHandler: unknown error !!!")); + } + } + image->Destroy(); + return FALSE; + } - return FALSE; + return TRUE; } -bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +bool wxPCXHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool verbose ) { if (verbose) - wxLogDebug(_T("wxPCXHandler::SaveFile still not implemented")); + wxLogError(wxT("wxPCXHandler::SaveFile still not implemented")); return FALSE; } -bool wxPCXHandler::CanRead( wxInputStream& stream ) +bool wxPCXHandler::DoCanRead( wxInputStream& stream ) { - return FALSE; -} + unsigned char c; + off_t pos; + pos = stream.TellI(); + stream.SeekI(0, wxFromStart); + c = stream.GetC(); + stream.SeekI(pos, wxFromStart); -#endif // wxUSE_STREAMS + // not very safe, but this is all we can get from PCX header :-( + return (c == 10); +} +#endif // wxUSE_STREAMS && wxUSE_PCX