Skip to content

Instantly share code, notes, and snippets.

@cls
Last active March 18, 2018 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cls/394484a79fc5eca33eb2be21715269a3 to your computer and use it in GitHub Desktop.
Save cls/394484a79fc5eca33eb2be21715269a3 to your computer and use it in GitHub Desktop.
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