add ff2jpg tool, convert farbfeld images to RGB JPEG - farbfeld - suckless imag… | |
git clone git://git.suckless.org/farbfeld | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 34e9cba51f5149da0670b32101e23b4d76e20d61 | |
parent 7f295f8c100a504c305d537bd3fde6492f15ef7a | |
Author: Hiltjo Posthuma <[email protected]> | |
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(-) | |
--- | |
diff --git a/LICENSE b/LICENSE | |
@@ -15,5 +15,5 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARIS… | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
(c) 2014-2015 Dimitris Papastamos <[email protected]> | |
-(c) 2014-2015 Hiltjo Posthuma <[email protected]> | |
+(c) 2014-2016 Hiltjo Posthuma <[email protected]> | |
(c) 2015 Willy Goiffon <[email protected]> | |
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} [email protected] | |
-jpg2ff: | |
+jpg2ff ff2jpg: | |
@echo CC $@ | |
@${CC} -o $@ ${CFLAGS} ${CPPFLAGS} -L${JPGLIB} -ljpeg -I${JPGINC} \ | |
${LDFLAGS} [email protected] | |
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 [email protected] | |
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(err… | |
+ 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; | |
+} |