Last active
January 22, 2016 00:27
-
-
Save kakwa/4e1ef87ab445f975ee84 to your computer and use it in GitHub Desktop.
uncompress Windows RLE8 to get bitmap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stddef.h> /* for offsetof() macro */ | |
#include <string.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <unistd.h> | |
typedef struct _dibImg { | |
char *img; | |
size_t size; | |
uint32_t width; | |
uint32_t height; | |
} bidImg; | |
#define RLE_MARK 0x00 | |
#define RLE_EOL 0x00 | |
#define RLE_EOB 0x01 | |
#define RLE_DELTA 0x02 | |
// uncompress RLE8 to get bitmap (section 3.1.6.2 [MS-WMF].pdf) | |
bidImg rle8ToBitmap(bidImg img) { | |
FILE *stream; | |
bool decode = true; | |
char *out; | |
size_t size; | |
bidImg out_img; | |
out_img.size = 0; | |
out_img.width = 0; | |
out_img.height = 0; | |
out_img.img = NULL; | |
uint8_t *bm = (uint8_t *)img.img; | |
uint32_t x = 0; | |
uint32_t y = img.height - 1; | |
uint8_t *bm_next; | |
stream = open_memstream(&out, &size); | |
if (stream == NULL) { | |
return out_img; | |
} | |
uint8_t *end = bm + img.size; | |
while (decode && (bm < end)) { | |
switch (bm[0]) { | |
// check against potential overflow | |
if ((bm + 2) > end) { | |
fclose(stream); | |
return out_img; | |
}; | |
case RLE_MARK: | |
switch (bm[1]) { | |
case RLE_EOL: | |
// end of line, pad the rest of the line with zeros | |
for (int i = 0; i < (img.width - x); i++) | |
fputc(0x00, stream); | |
bm += 2; | |
x = 0; | |
y--; | |
break; | |
case RLE_EOB: | |
// end of bitmap | |
decode = false; | |
break; | |
case RLE_DELTA: | |
// offset handling, pad with (off.x + off.y * width) zeros | |
if ((bm + 3) > end) { | |
fclose(stream); | |
return out_img; | |
}; | |
for (int i = 0; i < (bm[2] + img.width * bm[3]); i++) | |
fputc(0x00, stream); | |
x += bm[2]; | |
y -= bm[3]; | |
bm += 4; | |
break; | |
default: | |
// absolute mode handling (no compression) | |
// data is padded to a word | |
// calculate next address accordingly | |
bm_next = bm + 1 + ((bm[1] + 1) / 2) * 2; | |
if (bm_next > end) { | |
fclose(stream); | |
return out_img; | |
}; | |
for (int i = 2; i < bm[1] + 2; i++) | |
fputc(bm[i], stream); | |
x += bm[1]; | |
bm = bm_next + 1; | |
break; | |
} | |
break; | |
default: | |
for (int i = 0; i < bm[0]; i++) | |
fputc(bm[1], stream); | |
x += bm[0]; | |
bm += 2; | |
if (x >= img.width) { | |
x = x % img.width; | |
y--; | |
} | |
break; | |
} | |
} | |
// pad the rest of the bitmap | |
for (int i = 0; i < ((img.width - x) + img.width * y); i++) | |
fputc(0x00, stream); | |
fflush(stream); | |
fclose(stream); | |
out_img.img = out; | |
out_img.size = size; | |
out_img.width = img.width; | |
out_img.height = img.height; | |
return out_img; | |
} | |
int main() { | |
char img[] = {0x03, 0x04, 0x05, 0x06, 0x00, 0x03, 0x45, 0x56, | |
0x67, 0x00, 0x02, 0x78, 0x00, 0x02, 0x05, 0x01, | |
0x02, 0x78, 0x00, 0x00, 0x09, 0x1E, 0x00, 0x01}; | |
bidImg in; | |
in.img = img; | |
in.width = 32; | |
in.height = 4; | |
in.size = 24; | |
printf("IN:\n"); | |
for (size_t i = 0; i < in.size; i++) { | |
printf("%02x ", in.img[i]); | |
} | |
printf("\n\n"); | |
printf("OUT:\n"); | |
bidImg out = rle8ToBitmap(in); | |
for (size_t i = 0; i < out.size; i++) { | |
printf("%02x ", out.img[i]); | |
if ((i % out.width) == 31) | |
printf("\n"); | |
} | |
printf("\n"); | |
} | |
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment