Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1449

[VB6] RLE8 Compression Algorithm for Bitmaps (Updated)

$
0
0
Updated. Added a few tweaks to the code to squeeze a few more bytes of compression. In some cases, it is significant, but on average, reduction of a couple hundred bytes achieved. See Post #2 for which ones I included & which still may be doable. Also updated the zip to include 2 more bitmaps: 1) one that this project & Windows can't compress smaller & 2) one where Windows can't compress, but this project compresses pretty well

Microsoft allows 8-bit bitmaps to be compressed using a somewhat simple, not terribly efficient, run length encoding (RLE). Strict rules apply, but is rather easy to encode/decode
Quote:

Originally Posted by paraphrased from msdn
Encoded runs cannot be larger than 255 bytes
Encoded scanlines terminate with a double null byte (end of line EOL)
Encoded bitmap terminates with bytes: 00 01 (EOF)
Scanlines are Word aligned, not DWord aligned
Associated BITMAPINFOHEADER fields required: biCompression=BI_RLE8: biSizeImage = size of encoded pixels

Encoding: can have several runs per scanline. Each run starts with a control byte:
01-255 indicates a repeated byte run length. The next byte is the repeated byte
00 indicates EOL, EOF or uncompressed run follows. Next byte determines meaning
00 = EOL
01 = EOF
02 = Delta followed by 2 byte "jump-to" coordinates. Not used in this project
03-255 = uncompressed run length & the uncompressed bytes follow
for odd length runs vs. even length, one padding byte is required at end of encoded run

Compression net gain(+)/loss(-) per run:
repeated byte runs: (length of run) - 2
uncompressed runs: if run is even number of bytes: net loss of 2 else net loss of 3
each scanline removes 2 bytes (EOL marker) from any net gain
loss of 2 bytes (EOF marker) from total net gain after all pixels encoded

Whether you are aware of it or not, you can actually get the API GetDibits to compress these 8-bit bitmaps for you. Niffty, fast, but unfortunately, what is returned can actually be larger than the original uncompressed image at times. In any case, I think we can do a bit better than Windows in this area.

Attached is a sample project wrapped around the key routine: pvCompressRLE8. Also included are 2 simple bitmaps to play with. Now trying to go out and find 8-bit bitmaps can be a bit painful, pun intended ;)
Suggestion: for playing around, use Microsoft Paint. Open image in Paint, save image as 256 color bitmap & don't care if the colors get messed up a bit. It's just for playing anyway

The routine I've written is not guaranteed to compress smaller than the total uncompressed size. But it should 99.9% of the time. In fact, it out-performs GetDibits every time (so far). I'm sure there are a few bitmaps that Windows can compress better via GetDibits.

This routine was created simply because I was inquisitive, wanted to see if I could possibly do it better (given how poorly Windows seems to do it). If there are better routines out there, please link them. Think many would like to learn from those also, me included.

Last but not least, I'm not touting this as the best RLE8 routine for VB6ers. But it ain't bad for a 1st attempt. The one I've included could use a little tune-up also. See post #2

Edited: Senior moment. Didn't include a browser class in the zip. It's there now.

FYI: If you want to see how Windows does when the routine fails to compress a bitmap, rem-out the "GoTo ExitRoutine" line after the msgbox displaying the failure

Best case scenario for failure and the "compressed" data being larger than the original data size would be a size equal to that shown below (assuming width < 256 else worse results). This is because if no bytes repeated on any scanline, the scanline would be coded with a 2 byte prefix + the entire scanline bytes + 2 byte scanline terminator. The encoding also requires a 2 byte EOF maker. But when compressing fails, the routine aborts so user can write bitmap in original bytes vs writing an even larger bitmap. Note: standard bitmaps without any compression algo applied have their pixels DWord aligned. This means for an 8-bit bitmap, a maximum of 3 padding bytes per scanline can be used for standard bitmaps. Even if that is the case, the minimum extra bytes used in RLE8 compression would be 4 per scanline. In other words, RLE8 without being able to compress any bytes, would be a larger file than not using RLE8 at all:
Code:

<best-case "compressed" size when bitmap cannot be compressed (not good)>
even-value image width: ImageHeight * 4 + 2 + (ImageHeight * ImageWidth)
odd-value image width: ImageHeight * 5 + 2  + (ImageHeight * ImageWidth)
^^ extra padding byte needed per scanline

Attached Files

Viewing all articles
Browse latest Browse all 1449

Trending Articles