RLE & Bitmaps

Started by
7 comments, last by LordLethis 21 years, 2 months ago
I wrote these functions to RLE compress a bitmap. But after compressing and decompressing the bitmap, i looks somewhat messed up (what I mean by 'messed up' can be seen here. Any ideas why? compress:
    
void rle(char* filename)
{
	BITMAPINFOHEADER ih;
	BITMAPFILEHEADER fh;
	RLEHEADER h;
	FILE* file = fopen(filename,"rb");
	fread(&fh,sizeof(fh),1,file);
	fread(&ih,sizeof(ih),1,file);
	if (fh.bfType!='MB' || ih.biBitCount != 24)
		return;
	RGB* data = (RGB*)malloc(ih.biWidth*ih.biHeight*3);
	int check = fread(data,3,ih.biWidth*ih.biHeight,file);
	fclose(file);
	RGBA* com = (RGBA*)calloc(ih.biWidth*ih.biHeight,sizeof(RGBA)); //make space for the worst case size -> every pixel has a different color

	h.quads = 0;
	memcpy(com,data,3);
	for (int i = 1; i < ih.biWidth*ih.biHeight; i++)
	{
		if (com[h.quads].r==data[i].r && com[h.quads].g==data[i].g && com[h.quads].b==data[i].b && com[h.quads].a < 255)
		{
			com[h.quads].a++;
		}
		else
		{
			h.quads++;
			memcpy(&com[h.quads],&data[i],3);
		}
	}
	h.type = 'ELR';
	h.height = ih.biHeight;
	h.width = ih.biWidth;
	h.bpp = ih.biBitCount;
	file = fopen("test.rle","wb");
	fwrite(&h,sizeof(h),1,file);
	check = fwrite(com,4,h.quads,file);
	fclose(file);
}
  

decompress:
      
void dec(char* filename)
{
	RLEHEADER h;
	BITMAPINFOHEADER ih;
	BITMAPFILEHEADER fh;
	FILE* file = fopen(filename,"rb");
	fread(&h,sizeof(h),1,file);
	if (h.type != 'ELR')
		return;
	RGBA* com = (RGBA*)malloc(4*h.quads);
	int check = fread(com,4,h.quads,file);
	fclose(file);
	RGB* data = (RGB*)malloc(3*h.height*h.width);
	memset(data,0,3*h.height*h.width);

	int c = 0, a = 0;
	
	for (int i = 0; i < h.height*h.width; i++)
	{
		if (a < com[c].a+1)
		{
			memcpy(&data[i],&com[c],3);
			a++;
		}
		else
		{
			c++;
			a = 0;
		}
	}

	fh.bfType = 'MB';
	fh.bfSize = sizeof(fh);
	fh.bfReserved1 = 0;
	fh.bfReserved2 = 0;
	fh.bfOffBits = sizeof(fh)+sizeof(ih);

	ih.biSize = sizeof(ih);
	ih.biWidth = h.width;
	ih.biHeight = h.height;
	ih.biPlanes = 1;
	ih.biBitCount = h.bpp;
	ih.biCompression = BI_RGB;
	ih.biSizeImage = 3*h.width*h.height;
	ih.biXPelsPerMeter = 2835; // 72 dpi

	ih.biYPelsPerMeter = 2835; // 72 dpi

	ih.biClrUsed = 0;
	ih.biClrImportant = 0;

	file = fopen("test.rle.bmp","w");
	fwrite(&fh,sizeof(fh),1,file);
	fwrite(&ih,sizeof(ih),1,file);
	fwrite(data,ih.biSizeImage,1,file);
	fclose(file);
}
    
[My Lousy Page|Kings Of Chaos | email.me] [edited by - LordLethis on January 28, 2003 11:51:29 AM]
[My Lousy Page | Kings Of Chaos | Vampires | [email=lordlethis@hotmail.com]email.me[/email]]
Advertisement
I don''t really know anything about implmentation of the RLE algorithm but I saw some stuff in your code that may contribute to the screwed up bitmap. The loop in your rle function initializes its loop variable to 1... should this be 0 instead? Another suspicious line of code reads


h.type = ''ELR'';


I''m not quite sure what happens when you put three characters inside single quotes... should these be double quotes? And if so, should you be using a string copy? Also, when returning from that same function about 8 lines into it you should make sure to close the file.

Like I said, I don''t really know what the heck I''m talking about, so I wouldn''t be surprised if any (or all, more likely!) of this is flat out wrong. Good luck!

-Glyph
although I didnt look over your code that thouroghly there is only one thing I can think of that could twist the bitmap like that is that you might not be padding the bytes at the end. Say for example you had a 63 pixel long bitmap, when you write the bitmap it should have 63 bytes worth of data (compressed of corse) but at the end of it needs to be null so that it is 64 bytes long. Bitmaps have to be compressed to the 4 byte boundery
ASCII stupid question, get a stupid ANSI
OK, I forgot to mention, the functions don''t performthe RLE used for .bmp''s, it''s an own developed RLE using the alpha channel to store the run length.
The counter var in the for loop is initialized with 1 on purpose. (Damnit, would be happy to find a fault )
Thanks for the help anyway!

- Lethis

[My Lousy Page|Kings Of Chaos | email.me]
[My Lousy Page | Kings Of Chaos | Vampires | [email=lordlethis@hotmail.com]email.me[/email]]
Argh!
I've just checked through every single byte of the two files, and they are identically (I didn't check manually ) This can't be

EDIT: Ouch!! They aren't. Had && in comparison statement instead of ||.

[My Lousy Page | Kings Of Chaos | email.me]

[edited by - LordLethis on January 29, 2003 9:29:49 AM]
[My Lousy Page | Kings Of Chaos | Vampires | [email=lordlethis@hotmail.com]email.me[/email]]
Try changing the start loop variable to 0. Just humor us.

-- John
If I start the loop var with 0 I''d copy the first pixel two times. That''s not what I intend to do, though.
[My Lousy Page | Kings Of Chaos | Vampires | [email=lordlethis@hotmail.com]email.me[/email]]
Ok, there''s two errors in the code.

1) The compression algorithm doesn''t save out the last run length (so if you had a 10x10 single colour bitmap, no colour data would be written to the output). To fix this, add
if (com [h.quads].a > 0)
{
++h.quads;
}
after the ''for'' loop in the ''rle'' function.

2) The decompressor is skipping pixels whenever a change of colour is occuring. This initially confused me when looking at the output image as the number of red pixels was correct but the number of black pixels to the left and right of the red block had gone up by two! To fix this, remove the ''i++'' form the ''for'' loop in the ''dec'' function and add it after the ''a++'' and before the ''}''.

Sorted.

If the background was not black, the problems would have been easier to spot and fix.

Skizz
Thanks very much, Skizz!!
Wouldn''t have spotted this myself, but I''ll remember this as it''s a pretty bad mistake.

- Lethis

[My Lousy Page | Kings Of Chaos | | email.me]
[My Lousy Page | Kings Of Chaos | Vampires | [email=lordlethis@hotmail.com]email.me[/email]]

This topic is closed to new replies.

Advertisement