Sign in to follow this  

Pcx decoder and drawer problem

This topic is 3314 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everybody, I wrote a simple pcx decoder but it doesn't work as I expect so I hope you can help me find the bug(s). Each scanline of the image is decoded and stored in a 1-dimensional array img->pixels.The problem is that the image doesn't show up correctly, sometimes appearing half correctly half white, others totally messed up... Here is the code
#include <stdio.h>
#include "SDL/SDL.h"

#define BYTE unsigned char
#define TWOBYTES short int
#define SCREEN_WIDTH 400
#define SCREEN_HEIGTH 400
#define SCREEN_BPP 32

SDL_Surface *screen;
typedef struct
{
	SDL_Color palette[256];
	int w;
	int h;
	BYTE *pixels; /* indexes to palette array */
} sprite_t;

int PcxHeader(FILE *f,int *w, int *h, int *NPlanes, int *BytesPerLine)
{
	typedef struct
	{
		BYTE Manufacturer;
		BYTE Version;
		BYTE Encoding;
		BYTE BitsPerPixel;
		TWOBYTES XStart, YStart;
		TWOBYTES XEnd, YEnd;
		BYTE NotUsed1[52];
		BYTE Reserved;
		BYTE NPlanes;
		TWOBYTES BytesPerLine;
	} pcx_t;
	pcx_t H;

	/* Reads the header */
	fread(&H, sizeof(pcx_t), 1, f);

	/* Checks if image is ok */
	if (H.Manufacturer != 10	|| 
		H.Version != 5			||
		H.Encoding != 1			||
		H.BitsPerPixel != 8		||
		H.Reserved != 0
		)
		return 1;

	*w = H.XEnd - H.XStart + 1;
	*h = H.YEnd - H.YStart + 1;
	*NPlanes = H.NPlanes;
	*BytesPerLine = H.BytesPerLine;

	return 0;

}

int PcxPalette(FILE *f,SDL_Color *palette)
{
	int i;
	char c;
	/* Reads the 256 colors' palette located in the last 768 bytes of the file */
	if ((c = fgetc(f)) != 12)
	{
		printf("codice palette errato %d\n",c);
		return 1;
	}

	/* Writes the palette */
	for (i=0; i<256; i++)
	{
		palette[i].r = fgetc(f);
		palette[i].g = fgetc(f);
		palette[i].b = fgetc(f);
	}

	return 0;
}



int PcxScanLine(FILE *f, BYTE *buffer, int buffsize)
{
	BYTE c;
	static int runcount = 0; /* static, so we keep the value for the next scan lines */
	static int runvalue = 0;
	int decodedBytes = 0;

	while (decodedBytes < buffsize)
	{
		if (runcount == 0)
		{
			c = fgetc(f);

			if ((c & 0xC0) == 0xC0)
			{
				runcount = c & 0x3F;
				runvalue = fgetc(f);
			}
			else
			{
				runcount = 1;
				runvalue = c;
			}
		}

		for ( ; runcount && decodedBytes < buffsize; runcount--)
		{
			buffer[decodedBytes] = runvalue;
			decodedBytes++;
		}

	}


	return decodedBytes;
}


sprite_t *LoadPcx(char *filename)
{
	BYTE *scanLineBuffer;
	FILE *f,*fw;
	sprite_t *img;
	int i, j, TotalBytes, NPlanes, BytesPerLine;

	img = (sprite_t *)malloc(sizeof(sprite_t));
	if (img == NULL)
	{
		printf("Non c'è abbastanza memoria per allocare l'immagine\n");
		return NULL;
	}

	// Opening file
	f = fopen(filename, "r");
	if (f == NULL)
	{
		printf("Impossibile aprire il file\n");
		return NULL;
	}

	// Reads the header and stores img->w and img->h 
	if (PcxHeader(f,&img->w, &img->h,&NPlanes, &BytesPerLine) == 1)
	{
		printf("Errore nell'header del file\n");
		return NULL;
	}

	fseek(f, -769, SEEK_END);
	if (PcxPalette(f, img->palette) == 1)
	{
		printf("Errore nel trovare la palette\n");
		return NULL;
	}

	/* Back to the image */
	fseek(f,128,SEEK_SET);

	img->pixels = (BYTE *)malloc(img->w * img->h * sizeof(BYTE));



	TotalBytes = NPlanes * BytesPerLine; // always an even number

	printf("Totalbytes: %d\n", TotalBytes);

	scanLineBuffer = (BYTE *)malloc(TotalBytes * sizeof(BYTE));

	for (i=0; i<img->h; i++)
	{

		PcxScanLine(f, scanLineBuffer, TotalBytes);

		for (j=0; j<img->w; j++)
		{
			img->pixels[i * img->w + j] = scanLineBuffer[j];
		}
	}

	free(scanLineBuffer);

	fclose(f);
	return img;
}

void DrawPixel(int x, int y, SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b)
{
	Uint32 color;
	Uint32 *pixmem;

	color = SDL_MapRGB( surface->format, r, g, b );
	pixmem = (Uint32*)surface->pixels + x + SCREEN_WIDTH * y;
	SDL_LockSurface(surface);
	*pixmem = color;
	SDL_UnlockSurface(surface);
}

int main(int argc, char *argv[])
{
	int i;
	sprite_t *img = LoadPcx("Ship.pcx");
	if (img == NULL) exit(1);

	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) exit(1); 
	screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGTH, SCREEN_BPP, SDL_SWSURFACE );

	printf("img w: %d\n", img->w);

	printf("img h: %d\n", img->h);
	
	for (i=0; i<img->w * img->h; i++)
	{
		DrawPixel(i % img->w, i / img->w, screen, img->palette[ img->pixels[i] ].r,  img->palette[ img->pixels[i] ].g, img->palette[ img->pixels[i] ].b);
		//printf("%d\n",img->pixels[i]);
	}
	
	SDL_Flip(screen);	
	SDL_Delay(100000000); // don't pay attention to it
	return 0;
}
hope you can help me thanks :)

Share this post


Link to post
Share on other sites
Quote:
Original post by David_pb
The indices have to be: img->palette[ img->pixels[i]*3 ].r, ...

- Dave


the image had the palette so 1 bitplane..
But I solved the problem..I had to fopen the file in binary mode..not text mode even though I scan it char by char..

Share this post


Link to post
Share on other sites

This topic is 3314 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this