farbfeld

suckless image format with conversion tools
git clone git://git.suckless.org/farbfeld
Log | Files | Refs | README | LICENSE

commit dc512d040c7d081ed96b1919420aebd646968879
parent e637aae67ededf6a4a0b4d490d02f3294f297b71
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Mon, 21 Mar 2016 21:06:06 +0100

add ff2ppm(1)

ff2ppm can convert farbfeld images to PPM (P6 binary format, 24-bit RGB).
ff2ppm has an option -b to set the background color, for example for png files:

png2ff < test.png | ff2ppm -b '#00ff00' > test.ppm

Diffstat:
Makefile | 7++++---
ff2ppm.1 | 48++++++++++++++++++++++++++++++++++++++++++++++++
ff2ppm.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,12 +2,13 @@ # See LICENSE file for copyright and license details include config.mk -BIN = png2ff ff2png jpg2ff +BIN = png2ff ff2png jpg2ff ff2ppm SRC = ${BIN:=.c} +HDR = arg.h MAN1 = 2ff.1 ${BIN:=.1} MAN5 = farbfeld.5 -all: png2ff ff2png jpg2ff +all: png2ff ff2png jpg2ff ff2ppm .c: @echo CC $< @@ -21,7 +22,7 @@ dist: clean @echo creating dist tarball @mkdir -p farbfeld-${VERSION} @cp -R FORMAT LICENSE Makefile README TODO config.mk \ - 2ff ${SRC} ${MAN1} ${MAN5} farbfeld-${VERSION} + 2ff ${HDR} ${SRC} ${MAN1} ${MAN5} farbfeld-${VERSION} @tar -cf farbfeld-${VERSION}.tar farbfeld-${VERSION} @gzip farbfeld-${VERSION}.tar @rm -rf farbfeld-${VERSION} diff --git a/ff2ppm.1 b/ff2ppm.1 @@ -0,0 +1,48 @@ +.Dd 2016-03-21 +.Dt FF2PPM 1 +.Os suckless.org +.Sh NAME +.Nm ff2ppm +.Nd convert farbfeld to PPM (binary) +.Sh SYNOPSIS +.Nm +.Op Fl b Ar color +.Sh DESCRIPTION +.Nm +reads a +.Xr farbfeld 5 +image from stdin, converts it to a PPM image (P6 binary format, RGB) and +writes the result to stdout. +.Pp +In case of an error +.Nm +writes a diagnostic message to stderr. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl b Ar color +.Ar color +to mix with the background alpha channel, the default is white. +.Pp +The following formats are supported: +"#rrggbb", "#rrrrggggbbbb" and the short-form "#rgb" which expands to "#rrggbb". +.El +.Sh EXIT STATUS +.Bl -tag -width Ds +.It 0 +Image processed successfully. +.It 1 +An error occurred. +.El +.Sh EXAMPLES +$ +png2ff < test.png | +.Nm +-b '#00ff00' > test.ppm +.Sh SEE ALSO +.Xr 2ff 1 , +.Xr bunzip2 1 , +.Xr bzip2 1 , +.Xr png2ff 1 , +.Xr farbfeld 5 +.Sh AUTHORS +.An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org diff --git a/ff2ppm.c b/ff2ppm.c @@ -0,0 +1,125 @@ +/* See LICENSE file for copyright and license details. */ +#include <arpa/inet.h> + +#include <errno.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arg.h" + +char *argv0; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-b #rrggbb]\n", argv0); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + size_t rowlen; + uint32_t hdr[4], width, height, i, j, k; + uint16_t *row, mr = 0xffff, mg = 0xffff, mb = 0xffff; + uint8_t *rowout; + char *color; + unsigned int r = 0xff, g = 0xff, b = 0xff; + float a; + + argv0 = argv[0]; + ARGBEGIN { + case 'b': + for (color = EARGF(usage()); *color && *color == '#'; color++) + ; + + switch (strlen(color)) { + case 3: + if (sscanf(color, "%1x%1x%1x", &r, &g, &b) != 3) + usage(); + mr = (r | r << 4) * 257; + mg = (g | g << 4) * 257; + mb = (b | b << 4) * 257; + break; + case 6: + if (sscanf(color, "%2x%2x%2x", &r, &g, &b) != 3) + usage(); + mr = r * 257; + mg = g * 257; + mb = b * 257; + break; + case 12: + if (sscanf(color, "%4x%4x%4x", &r, &g, &b) != 3) + usage(); + mr = r; + mg = g; + mb = b; + break; + default: + usage(); + } + break; + default: + usage(); + } ARGEND + + if (argc) + usage(); + + /* header */ + if (fread(hdr, sizeof(*hdr), 4, stdin) != 4) { + fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); + return 1; + } + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { + fprintf(stderr, "%s: invalid magic value\n", argv0); + return 1; + } + if (!(width = ntohl(hdr[2]))) { + fprintf(stderr, "%s: invalid width: zero\n", argv0); + return 1; + } + if (!(height = ntohl(hdr[3]))) { + fprintf(stderr, "%s: invalid height: zero\n", argv0); + return 1; + } + if (width > SIZE_MAX / ((sizeof("RGBA") - 1) * sizeof(uint16_t))) { + fprintf(stderr, "%s: row length integer overflow\n", argv0); + return 1; + } + + rowlen = width * (sizeof("RGBA") - 1); + if (!(row = malloc(rowlen * sizeof(uint16_t)))) { + fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); + return 1; + } + if (!(rowout = malloc(width * sizeof("RGB") - 1))) { + fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); + return 1; + } + + /* PPM binary */ + printf("P6\n%" PRIu32 " %" PRIu32 "\n255\n", width, height); + + /* write rows */ + for (i = 0; i < height; ++i) { + if (fread(row, sizeof(uint16_t), rowlen, stdin) != rowlen) { + fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); + return 1; + } + for (j = 0, k = 0; j < rowlen; j += 4, k += 3) { + a = ntohs(row[j + 3]) / 65535.0f; + rowout[k] = ((ntohs(row[j]) * a) + (mr * (1 - a))) / 257; + rowout[k + 1] = ((ntohs(row[j + 1]) * a) + (mg * (1 - a))) / 257; + rowout[k + 2] = ((ntohs(row[j + 2]) * a) + (mb * (1 - a))) / 257; + } + if (fwrite(rowout, 3, width, stdout) != width) { + fprintf(stderr, "%s: fwrite: %s\n", argv0, strerror(errno)); + return 1; + } + } + return 0; +}