Some more work on reading pcx files.
git-svn-id: svn://svn.cc65.org/cc65/trunk@5554 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
c4721fb4e2
commit
6893f52a50
4 changed files with 165 additions and 66 deletions
|
@ -65,7 +65,8 @@ Bitmap* NewBitmap (unsigned Width, unsigned Height)
|
|||
|
||||
/* Initialize the data */
|
||||
B->Type = bmUnknown;
|
||||
SB_Init (&B->Name);
|
||||
B->Name = EmptyStrBuf;
|
||||
B->Tag = 0;
|
||||
B->Width = Width;
|
||||
B->Height = Height;
|
||||
B->Pal = 0;
|
||||
|
@ -79,8 +80,10 @@ Bitmap* NewBitmap (unsigned Width, unsigned Height)
|
|||
void FreeBitmap (Bitmap* B)
|
||||
/* Free a dynamically allocated bitmap */
|
||||
{
|
||||
/* Free the palette */
|
||||
/* Free the format specific data, the palette and then the bitmap */
|
||||
xfree (B->Tag);
|
||||
xfree (B->Pal);
|
||||
xfree(B);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@ struct Bitmap {
|
|||
*/
|
||||
StrBuf Name;
|
||||
|
||||
/* Pointer to some format specific data. May be used by the frontend.
|
||||
* The data is free'd as a block when calling FreeBitmap.
|
||||
*/
|
||||
void* Tag;
|
||||
|
||||
/* Size of the bitmap */
|
||||
unsigned Width;
|
||||
unsigned Height;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
/* common */
|
||||
#include "cmdline.h"
|
||||
#include "print.h"
|
||||
#include "version.h"
|
||||
|
||||
/* sp65 */
|
||||
|
@ -57,16 +58,18 @@
|
|||
static void Usage (void)
|
||||
/* Print usage information and exit */
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Usage: %s [options] file [options] [file]\n"
|
||||
"Short options:\n"
|
||||
" -h\t\t\tHelp (this text)\n"
|
||||
" -V\t\t\tPrint the version number and exit\n"
|
||||
"\n"
|
||||
"Long options:\n"
|
||||
" --help\t\tHelp (this text)\n"
|
||||
" --version\t\tPrint the version number and exit\n",
|
||||
ProgName);
|
||||
printf (
|
||||
"Usage: %s [options] file [options] [file]\n"
|
||||
"Short options:\n"
|
||||
" -V\t\t\tPrint the version number and exit\n"
|
||||
" -h\t\t\tHelp (this text)\n"
|
||||
" -v\t\t\tIncrease verbosity\n"
|
||||
"\n"
|
||||
"Long options:\n"
|
||||
" --help\t\tHelp (this text)\n"
|
||||
" --verbose\t\tIncrease verbosity\n"
|
||||
" --version\t\tPrint the version number and exit\n",
|
||||
ProgName);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,6 +84,15 @@ static void OptHelp (const char* Opt attribute ((unused)),
|
|||
|
||||
|
||||
|
||||
static void OptVerbose (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Increase versbosity */
|
||||
{
|
||||
++Verbosity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptVersion (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Print the assembler version */
|
||||
|
@ -98,6 +110,7 @@ int main (int argc, char* argv [])
|
|||
/* Program long options */
|
||||
static const LongOpt OptTab[] = {
|
||||
{ "--help", 0, OptHelp },
|
||||
{ "--verbose", 0, OptVerbose },
|
||||
{ "--version", 0, OptVersion },
|
||||
};
|
||||
|
||||
|
@ -121,13 +134,17 @@ int main (int argc, char* argv [])
|
|||
LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
OptVersion (Arg, 0);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
OptHelp (Arg, 0);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
OptVersion (Arg, 0);
|
||||
break;
|
||||
case 'v':
|
||||
OptVerbose (Arg, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
UnknownOption (Arg);
|
||||
|
|
176
src/sp65/pcx.c
176
src/sp65/pcx.c
|
@ -37,6 +37,10 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* common */
|
||||
#include "print.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* sp65 */
|
||||
#include "error.h"
|
||||
#include "fileio.h"
|
||||
|
@ -50,30 +54,38 @@
|
|||
|
||||
|
||||
|
||||
/* Size of the PCX header and other constants */
|
||||
#define PCX_HEADER_SIZE 128
|
||||
/* Some PCX constants */
|
||||
#define PCX_MAGIC_ID 0x0A
|
||||
|
||||
/* Type of a PCX header */
|
||||
typedef unsigned char PCXHeader[PCX_HEADER_SIZE];
|
||||
/* A raw PCX header is just a block of bytes */
|
||||
typedef unsigned char RawPCXHeader[128];
|
||||
|
||||
/* The following macros are used to access the PCX header, which is a 128 byte
|
||||
* block of raw data.
|
||||
*/
|
||||
/* Structured PCX header */
|
||||
typedef struct PCXHeader PCXHeader;
|
||||
struct PCXHeader {
|
||||
unsigned Id;
|
||||
unsigned FileVersion;
|
||||
unsigned Compressed;
|
||||
unsigned BPP;
|
||||
unsigned XMin;
|
||||
unsigned YMin;
|
||||
unsigned XMax;
|
||||
unsigned YMax;
|
||||
unsigned XDPI;
|
||||
unsigned YDPI;
|
||||
unsigned Planes;
|
||||
unsigned BytesPerPlane;
|
||||
unsigned PalInfo;
|
||||
unsigned ScreenWidth;
|
||||
unsigned ScreenHeight;
|
||||
|
||||
/* Calculated data */
|
||||
unsigned Width;
|
||||
unsigned Height;
|
||||
};
|
||||
|
||||
/* Read a little endian word from a byte array at offset O */
|
||||
#define WORD(H, O) ((H)[O] | ((H)[O+1] << 8))
|
||||
#define PCX_ID(H) ((H)[0])
|
||||
#define PCX_FILE_VERSION(H) ((H)[1])
|
||||
#define PCX_COMPRESSION(H) ((H)[2])
|
||||
#define PCX_BPP(H) ((H)[3])
|
||||
#define PCX_XMIN(H) WORD(H, 4)
|
||||
#define PCX_YMIN(H) WORD(H, 6)
|
||||
#define PCX_XMAX(H) WORD(H, 8)
|
||||
#define PCX_YMAX(H) WORD(H, 10)
|
||||
#define PCX_PLANES(H) ((H)[65])
|
||||
#define PCX_BYTES_PER_LINE(H) WORD(H, 66)
|
||||
#define PCX_PAL_INFO(H) WORD(H, 68)
|
||||
#define PCX_WIDTH(H) WORD(H, 70)
|
||||
#define PCX_HEIGHT(H) WORD(H, 72)
|
||||
|
||||
|
||||
|
||||
|
@ -83,13 +95,98 @@ typedef unsigned char PCXHeader[PCX_HEADER_SIZE];
|
|||
|
||||
|
||||
|
||||
static PCXHeader* NewPCXHeader (void)
|
||||
/* Allocate a new PCX header and return it */
|
||||
{
|
||||
/* No initialization here */
|
||||
return xmalloc (sizeof (PCXHeader));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PCXHeader* ReadPCXHeader (FILE* F, const char* Name)
|
||||
/* Read a structured PCX header from the given file and return it */
|
||||
{
|
||||
RawPCXHeader H;
|
||||
|
||||
/* Allocate a new PCXHeader structure */
|
||||
PCXHeader* P = NewPCXHeader ();
|
||||
|
||||
/* Read the raw header */
|
||||
ReadData (F, H, sizeof (H));
|
||||
|
||||
/* Convert the data into structured form */
|
||||
P->Id = H[0];
|
||||
P->FileVersion = H[1];
|
||||
P->Compressed = H[2];
|
||||
P->BPP = H[3];
|
||||
P->XMin = WORD (H, 4);
|
||||
P->YMin = WORD (H, 6);
|
||||
P->XMax = WORD (H, 8);
|
||||
P->YMax = WORD (H, 10);
|
||||
P->XDPI = WORD (H, 12);
|
||||
P->YDPI = WORD (H, 14);
|
||||
P->Planes = H[65];
|
||||
P->BytesPerPlane = WORD (H, 66);
|
||||
P->PalInfo = WORD (H, 68);
|
||||
P->ScreenWidth = WORD (H, 70);
|
||||
P->ScreenHeight = WORD (H, 72);
|
||||
P->Width = P->XMax - P->XMin + 1;
|
||||
P->Height = P->YMax - P->YMin + 1;
|
||||
|
||||
/* Check the header data */
|
||||
if (P->Id != PCX_MAGIC_ID || P->FileVersion == 1 || P->FileVersion > 5) {
|
||||
Error ("`%s' is not a PCX file", Name);
|
||||
}
|
||||
if (P->Compressed > 1) {
|
||||
Error ("Unsupported compression (%d) in PCX file `%s'",
|
||||
P->Compressed, Name);
|
||||
}
|
||||
if (P->BPP != 1 && P->BPP != 4 && P->BPP != 8) {
|
||||
Error ("Unsupported bit depth (%u) in PCX file `%s'",
|
||||
P->BPP, Name);
|
||||
}
|
||||
if (P->PalInfo != 1 && P->PalInfo != 2) {
|
||||
Error ("Unsupported palette info (%u) in PCX file `%s'",
|
||||
P->PalInfo, Name);
|
||||
}
|
||||
if (!ValidBitmapSize (P->Width, P->Height)) {
|
||||
Error ("PCX file `%s' has an unsupported size (w=%u, h=%d)",
|
||||
Name, P->Width, P->Height);
|
||||
}
|
||||
|
||||
/* Return the structured header */
|
||||
return P;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DumpPCXHeader (const PCXHeader* P, const char* Name)
|
||||
/* Dump the header of the PCX file in readable form to stdout */
|
||||
{
|
||||
printf ("File name: %s\n", Name);
|
||||
printf ("PCX Version: ");
|
||||
switch (P->FileVersion) {
|
||||
case 0: puts ("2.5"); break;
|
||||
case 2: puts ("2.8 with palette"); break;
|
||||
case 3: puts ("2.8 without palette"); break;
|
||||
case 4: puts ("PCX for Windows without palette"); break;
|
||||
case 5: puts ("3.0"); break;
|
||||
}
|
||||
printf ("Image type: %s\n", P->PalInfo? "color" : "grayscale");
|
||||
printf ("Compression: %s\n", P->Compressed? "RLE" : "None");
|
||||
printf ("Structure: %u planes of %u bits\n", P->Planes, P->BPP);
|
||||
printf ("Bounding box: [%u/%u - %u/%u]\n", P->XMin, P->YMin, P->XMax, P->YMax);
|
||||
printf ("Resolution: %u/%u DPI\n", P->XDPI, P->YDPI);
|
||||
printf ("Screen size: %u/%u\n", P->ScreenWidth, P->ScreenHeight);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Bitmap* ReadPCXFile (const char* Name)
|
||||
/* Read a bitmap from a PCX file */
|
||||
{
|
||||
PCXHeader H;
|
||||
unsigned Version, Compression;
|
||||
unsigned BPP, Planes, BytesPerLine;
|
||||
unsigned Width, Height;
|
||||
PCXHeader* P;
|
||||
Bitmap* B;
|
||||
|
||||
/* Open the file */
|
||||
|
@ -99,34 +196,11 @@ Bitmap* ReadPCXFile (const char* Name)
|
|||
}
|
||||
|
||||
/* Read the PCX header */
|
||||
ReadData (F, H, sizeof (H));
|
||||
P = ReadPCXHeader (F, Name);
|
||||
|
||||
/* Check the magic id byte */
|
||||
if (PCX_ID (H) != PCX_MAGIC_ID) {
|
||||
Error ("`%s' is not a PCX file", Name);
|
||||
}
|
||||
|
||||
/* Read more data */
|
||||
Version = PCX_FILE_VERSION (H);
|
||||
Compression = PCX_COMPRESSION (H);
|
||||
BPP = PCX_BPP (H);
|
||||
Planes = PCX_PLANES (H);
|
||||
BytesPerLine = PCX_BYTES_PER_LINE (H);
|
||||
Width = PCX_XMAX (H) - PCX_XMIN (H) + 1;
|
||||
Height = PCX_YMAX (H) - PCX_YMIN (H) + 1;
|
||||
|
||||
/* Check the data */
|
||||
if (Compression != 0 && Compression != 1) {
|
||||
Error ("Unsupported compression (%d) in PCX file `%s'",
|
||||
Compression, Name);
|
||||
}
|
||||
if (BPP != 1 && BPP != 4 && BPP != 8) {
|
||||
Error ("Unsupported bit depth (%d) in PCX file `%s'",
|
||||
BPP, Name);
|
||||
}
|
||||
if (!ValidBitmapSize (Width, Height)) {
|
||||
Error ("PCX file `%s' has an unsupported size (w=%u, h=%d)",
|
||||
Name, Width, Height);
|
||||
/* Dump the header if requested */
|
||||
if (Verbosity > 0) {
|
||||
DumpPCXHeader (P, Name);
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
|
|
Loading…
Add table
Reference in a new issue