ff2txt

display a farbfeld(5)-formatted image as braille or ascii text
Log | Files | Refs | README

commit dc898f91b9f862707348f36a08628a9b08f3525b
Author: Josuah Demangeon <mail@josuah.net>
Date:   Mon, 22 Jan 2018 05:41:32 +0100

Added ff2braille

Diffstat:
A.gitignore | 3+++
AMakefile | 8++++++++
Aff2braille.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.core +ff2braille diff --git a/Makefile b/Makefile @@ -0,0 +1,8 @@ +CFLAGS = -std=c89 -pedantic -Wall -Wextra -Werror +all: ff2braille + +ff2braille: ff2braille.o + cc -o $@ ff2braille.o $(LDFLAGS) + +clean: + rm -f *.o ff2braille diff --git a/ff2braille.c b/ff2braille.c @@ -0,0 +1,111 @@ +#include <arpa/inet.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "util.h" + +#define MAX_WIDTH (1 << 12) +#define BRAILLE_START 10240 +#define COLORS 4 + +#define LEN(X) (sizeof(X) / sizeof(*X)) + +struct col { + uint16_t red; + uint16_t green; + uint16_t blue; + uint16_t alpha; +}; + +void +err(char *msg) +{ + perror(msg); + exit(1); +} + +void +read_header(uint32_t *width, uint32_t *h) +{ + uint32_t header[4]; + + if (fread(header, sizeof(*header), LEN(header), stdin) != LEN(header)) + err("fread"); + + if (memcmp("farbfeld", header, sizeof("farbfeld") - 1)) + err("invalid magic value\n"); + + *width = ntohl(header[2]); + *h = ntohl(header[3]); +} + +void +print_utf8_3byte(long rune) +{ + printf("%c%c%c", + (char)(0xe0 | (0x0f & (rune >> 12))), /* 1110xxxx */ + (char)(0x80 | (0x3f & (rune >> 6))), /* 10xxxxxx */ + (char)(0x80 | (0x3f & (rune)))); /* 10xxxxxx */ +} + +int +is_on(struct col *rows[4], uint32_t width, uint32_t height, uint32_t w, + uint32_t h) +{ + uint16_t sum; + + if (w >= width || h >= height) + return 0; + + /* divide first to avoid overflow */ + sum = rows[h][w].red / 4; + sum += rows[h][w].green / 4; + sum += rows[h][w].blue / 4; + sum += rows[h][w].alpha / 4; + return sum >= UINT16_MAX / 2; +} + +void +print_4_rows(struct col *rows[4], uint32_t width, uint32_t height) +{ + uint32_t w; + + for (w = 0; w < width; w += 2) + print_utf8_3byte(BRAILLE_START + + 1 * is_on(rows, width, height, w + 0, 0) + + 8 * is_on(rows, width, height, w + 1, 0) + + 2 * is_on(rows, width, height, w + 0, 1) + + 16 * is_on(rows, width, height, w + 1, 1) + + 4 * is_on(rows, width, height, w + 0, 2) + + 32 * is_on(rows, width, height, w + 1, 2) + + 64 * is_on(rows, width, height, w + 0, 3) + + 128 * is_on(rows, width, height, w + 1, 3)); + putchar('\n'); +} + +int +main(void) +{ + struct col buf[MAX_WIDTH * 4], *rows[4]; + uint32_t width, height, r, i; + + read_header(&width, &height); + if (width == 0 || height == 0) + err("empty image"); + + for (i = 0; i < 4; i++) + rows[i] = buf + width * i; + + for (; height > 0; height -= 4) { + r = fread(buf, sizeof(*buf), width * 4, stdin); + if (r % width != 0) + err("invalid line width"); + print_4_rows(rows, width, r / width); + } + if (ferror(stdin)) + err("fread stdin"); + return 0; +}