add ff2jpg tool, convert farbfeld images to RGB JPEG - 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 34e9cba51f5149da0670b32101e23b4d76e20d61
 (DIR) parent 7f295f8c100a504c305d537bd3fde6492f15ef7a
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Thu, 24 Mar 2016 19:17:48 +0100
       
       add ff2jpg tool, convert farbfeld images to RGB JPEG
       
       Diffstat:
         M LICENSE                             |       2 +-
         M Makefile                            |       4 ++--
         A ff2jpg.1                            |      56 +++++++++++++++++++++++++++++++
         A ff2jpg.c                            |     151 +++++++++++++++++++++++++++++++
       
       4 files changed, 210 insertions(+), 3 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       @@ -15,5 +15,5 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        
        (c) 2014-2015 Dimitris Papastamos <sin@2f30.org>
       -(c) 2014-2015 Hiltjo Posthuma <hiltjo@codemadness.org>
       +(c) 2014-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
        (c) 2015 Willy Goiffon <willy@mailoo.org>
 (DIR) diff --git a/Makefile b/Makefile
       @@ -2,7 +2,7 @@
        # See LICENSE file for copyright and license details
        include config.mk
        
       -BIN = png2ff ff2png jpg2ff ff2ppm
       +BIN = png2ff ff2png jpg2ff ff2jpg ff2ppm
        SRC = ${BIN:=.c}
        HDR = arg.h
        MAN1 = 2ff.1 ${BIN:=.1}
       @@ -15,7 +15,7 @@ png2ff ff2png:
                @${CC} -o $@ ${CFLAGS} ${CPPFLAGS} -L${PNGLIB} -lpng -I${PNGINC} \
                        ${LDFLAGS} $@.c
        
       -jpg2ff:
       +jpg2ff ff2jpg:
                @echo CC $@
                @${CC} -o $@ ${CFLAGS} ${CPPFLAGS} -L${JPGLIB} -ljpeg -I${JPGINC} \
                        ${LDFLAGS} $@.c
 (DIR) diff --git a/ff2jpg.1 b/ff2jpg.1
       @@ -0,0 +1,56 @@
       +.Dd 2016-03-23
       +.Dt FF2JPG 1
       +.Os suckless.org
       +.Sh NAME
       +.Nm ff2jpg
       +.Nd convert farbfeld to JPEG
       +.Sh SYNOPSIS
       +.Nm
       +.Op Fl b Ar color
       +.Op Fl o
       +.Op Fl q Ar quality
       +.Sh DESCRIPTION
       +.Nm
       +reads a
       +.Xr farbfeld 5
       +image from stdin, converts it to a JPEG image (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".
       +.It Fl o
       +Optimize Huffman table (smaller file, but slow compression).
       +.It Fl q Ar quality
       +set JPEG output
       +.Ar quality
       +(range 0-100), the default is 85.
       +.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' -q 85 > test.jpg
       +.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/ff2jpg.c b/ff2jpg.c
       @@ -0,0 +1,151 @@
       +/* 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 <jpeglib.h>
       +
       +#include "arg.h"
       +
       +char *argv0;
       +
       +METHODDEF(void)
       +jpeg_error(j_common_ptr js)
       +{
       +        fprintf(stderr, "%s: libjpeg: ", argv0);
       +        (*js->err->output_message)(js);
       +        exit(1);
       +}
       +
       +static void
       +usage(void)
       +{
       +        fprintf(stderr, "usage: %s [-b #rrggbb] [-o] [-q quality]\n", argv0);
       +        exit(1);
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        JSAMPROW row_pointer[1]; /* pointer to a single row */
       +        struct jpeg_compress_struct cinfo;
       +        struct jpeg_error_mgr jerr;
       +        size_t rowlen;
       +        uint64_t a;
       +        uint32_t hdr[4], width, height, i, j, k, l;
       +        uint16_t *row, mask[3] = { 0xffff, 0xffff, 0xffff };
       +        uint8_t *rowout;
       +        char *color, colfmt[] = "%#x%#x%#x";
       +        unsigned int collen, col[3], colfac, quality = 85, optimize = 0;
       +
       +        argv0 = argv[0];
       +        ARGBEGIN {
       +        case 'b':
       +                color = EARGF(usage());
       +                if (color[0] == '#') {
       +                        color++;
       +                }
       +                collen = strlen(color);
       +                if (collen != 3 && collen != 6 && collen != 12) {
       +                        usage();
       +                }
       +                colfmt[1] = colfmt[4] = colfmt[7] = ((collen / 3) + '0');
       +                if (sscanf(color, colfmt, col, col + 1, col + 2) != 3) {
       +                        usage();
       +                }
       +                /* UINT16_MAX / 255 = 257; UINT16_MAX / 15 = 4369 */
       +                colfac = (collen == 3) ? 4369 : (collen == 6) ? 257 : 1;
       +                for (i = 0; i < 3; i++) {
       +                        mask[i] = col[i] * colfac;
       +                }
       +                break;
       +        case 'o':
       +                optimize = 1;
       +                break;
       +        case 'q':
       +                if ((quality = atoi(EARGF(usage()))) > 100)
       +                        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) * sizeof(uint8_t)))) {
       +                fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno));
       +                return 1;
       +        }
       +        row_pointer[0] = rowout;
       +
       +        jerr.error_exit = jpeg_error;
       +
       +        jpeg_create_compress(&cinfo);
       +        cinfo.err = jpeg_std_error(&jerr);
       +        jpeg_stdio_dest(&cinfo, stdout);
       +        cinfo.image_width = width;
       +        cinfo.image_height = height;
       +        cinfo.input_components = 3;  /* color components per pixel */
       +        cinfo.in_color_space = JCS_RGB; /* output color space */
       +        jpeg_set_defaults(&cinfo);
       +        if (optimize)
       +                cinfo.optimize_coding = TRUE;
       +        jpeg_set_quality(&cinfo, quality, TRUE);
       +
       +        jpeg_start_compress(&cinfo, TRUE);
       +
       +        /* 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]);
       +                        for (l = 0; l < 3; l++) {
       +                                rowout[k + l] = (a * ntohs(row[j + l]) +
       +                                                 (65535 - a) * mask[l]) /
       +                                                (257 * 65535);
       +                        }
       +                }
       +                jpeg_write_scanlines(&cinfo, row_pointer, 1);
       +        }
       +
       +        jpeg_finish_compress(&cinfo);
       +        jpeg_destroy_compress(&cinfo);
       +
       +        return 0;
       +}