Translate raw two-dimensional bitmap into word-aligned rows
#include <stdint.h> | |
#include <string.h> | |
void | |
row_align(uint8_t *dst, const uint8_t *src, const size_t width_in_bits, const size_t height) | |
{ | |
const size_t width_in_whole_bytes = width_in_bits / 8; | |
if (width_in_bits % 32 == 0) { // word-aligned | |
memcpy(dst, src, width_in_whole_bytes * height); | |
return; | |
} | |
const size_t width_in_partial_bytes = (width_in_bits + 7) / 8; | |
const size_t width_in_aligned_bytes = ((width_in_partial_bytes + 3) / 4) * 4; | |
const size_t overhang = width_in_bits % 8; | |
if (overhang == 0) { // byte-aligned | |
for (size_t row = 0; row < height; row++) { | |
memcpy(dst, src, width_in_whole_bytes); | |
src += width_in_whole_bytes; | |
dst += width_in_aligned_bytes; | |
} | |
return; | |
} | |
uint8_t leftover; | |
size_t bits = 0; | |
for (size_t row = 0; row < height; row++) { | |
if (bits == 0) { | |
memcpy(dst, src, width_in_partial_bytes); | |
leftover = src[width_in_whole_bytes] << overhang; | |
src += width_in_partial_bytes; | |
bits = 8; | |
} | |
else { | |
for (size_t i = 0; i < width_in_whole_bytes; i++) { | |
const uint8_t byte = src[i]; | |
dst[i] = leftover | (byte >> bits); | |
leftover = byte << (8 - bits); | |
} | |
src += width_in_whole_bytes; | |
if (bits < overhang) { | |
const uint8_t byte = *src++; | |
dst[width_in_whole_bytes] = leftover | (byte >> bits); | |
leftover = byte << (overhang - bits); | |
bits += 8; | |
} | |
else { | |
dst[width_in_whole_bytes] = leftover; | |
leftover <<= overhang; | |
} | |
} | |
bits -= overhang; | |
dst += width_in_aligned_bytes; | |
} | |
} |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define MAX_WIDTH 64 | |
#define MAX_HEIGHT 64 | |
#define ALIGN(W) ((((W) + 31) / 32) * 32) | |
#define NELEM(X) (sizeof (X) / sizeof *(X)) | |
extern void row_align(uint8_t *, const uint8_t *, size_t, size_t); | |
static bool is_set(size_t, size_t, const uint8_t *, size_t); | |
int | |
main(void) | |
{ | |
uint8_t src[MAX_WIDTH * MAX_HEIGHT]; | |
uint8_t dst[ALIGN(MAX_WIDTH) * MAX_HEIGHT]; | |
int status = EXIT_SUCCESS; | |
for (size_t width = 1; width <= MAX_WIDTH; width++) { | |
for (size_t height = 1; height <= MAX_HEIGHT; height++) { | |
for (size_t i = 0; i < NELEM(src); i++) { | |
src[i] = rand(); | |
} | |
row_align(dst, src, width, height); | |
size_t errors = 0; | |
for (size_t y = 0; y < height; y++) { | |
for (size_t x = 0; x < width; x++) { | |
if (is_set(x, y, src, width) != is_set(x, y, dst, ALIGN(width))) { | |
errors++; | |
} | |
} | |
} | |
if (errors != 0) { | |
fprintf(stderr, "%zux%zu: %zu errors\n", width, height, errors); | |
status = EXIT_FAILURE; | |
} | |
} | |
} | |
return status; | |
} | |
bool | |
is_set(size_t x, size_t y, const uint8_t *data, size_t wrap) | |
{ | |
const size_t index = (y * wrap) + x; | |
const size_t byte = index / 8; | |
const size_t bit = index % 8; | |
return data[byte] & ((1 << 7) >> bit); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment