farbfeld

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

commit 34e9cba51f5149da0670b32101e23b4d76e20d61
parent 7f295f8c100a504c305d537bd3fde6492f15ef7a
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:
MLICENSE | 2+-
MMakefile | 4++--
Aff2jpg.1 | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aff2jpg.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 210 insertions(+), 3 deletions(-)

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> 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 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 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; +}