add ff2ppm(1) - farbfeld - suckless image format with conversion tools
 (HTM) git clone git://git.suckless.org/farbfeld
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit dc512d040c7d081ed96b1919420aebd646968879
 (DIR) parent e637aae67ededf6a4a0b4d490d02f3294f297b71
 (HTM) 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:
         M Makefile                            |       7 ++++---
         A ff2ppm.1                            |      48 +++++++++++++++++++++++++++++++
         A ff2ppm.c                            |     125 +++++++++++++++++++++++++++++++
       
       3 files changed, 177 insertions(+), 3 deletions(-)
       ---
 (DIR) 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}
 (DIR) 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
 (DIR) 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;
       +}