1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-29 10:29:30 +00:00

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:
uz 2012-02-26 11:54:05 +00:00
parent c4721fb4e2
commit 6893f52a50
4 changed files with 165 additions and 66 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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 */