diff options
author | Paride Legovini <pl@ninthfloor.org> | 2017-07-16 17:36:46 +0200 |
---|---|---|
committer | Paride Legovini <pl@ninthfloor.org> | 2017-07-16 17:36:46 +0200 |
commit | 31cb65d7cc6d257bcc725ef39ffbced7b465f0cc (patch) | |
tree | 28d325b462a84b8a16bd2e9aa546df75dcd1b664 | |
parent | ed0e5905eff7383b05b87ecf1689a6938f9d79d3 (diff) | |
parent | 00dd0ab39f634729ec5d99b8057b9cef6fa0f23e (diff) |
Merge tag '3'
-rwxr-xr-x | 2ff | 51 | ||||
-rw-r--r-- | 2ff.1 | 18 | ||||
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | Makefile | 68 | ||||
-rw-r--r-- | README | 51 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | config.mk | 31 | ||||
-rw-r--r-- | farbfeld.5 | 130 | ||||
-rw-r--r-- | ff2jpg.1 | 34 | ||||
-rw-r--r-- | ff2jpg.c | 139 | ||||
-rw-r--r-- | ff2pam.1 | 7 | ||||
-rw-r--r-- | ff2pam.c | 66 | ||||
-rw-r--r-- | ff2png.1 | 8 | ||||
-rw-r--r-- | ff2png.c | 102 | ||||
-rw-r--r-- | ff2ppm.1 | 28 | ||||
-rw-r--r-- | ff2ppm.c | 88 | ||||
-rw-r--r-- | jpg2ff.1 | 5 | ||||
-rw-r--r-- | jpg2ff.c | 109 | ||||
-rw-r--r-- | png2ff.1 | 5 | ||||
-rw-r--r-- | png2ff.c | 111 | ||||
-rw-r--r-- | util.c | 238 | ||||
-rw-r--r-- | util.h | 22 |
22 files changed, 756 insertions, 560 deletions
@@ -1,41 +1,44 @@ #!/bin/sh + +# arguments if [ "$#" -ne 0 ]; then echo "usage: $0" >&2 exit 1 fi +# write input into temporary file TMP=$(mktemp) trap 'rm "$TMP"' EXIT - cat > "$TMP" -if [ "$(dd if="$TMP" bs=1 count=8 2>/dev/null)" = "farbfeld" ]; then +# determine the mime-type +if [ "$(dd if="$TMP" bs=1 count=8 2>/dev/null | tr -d '\0')" = "farbfeld" ]; then cat "$TMP" - exit 0 -fi +else + MIME=$(file -ib "$TMP" | cut -d ";" -f 1) -FORMAT=$(file -ib "$TMP" | cut -d ";" -f 1) + case "$MIME" in + image/png) + png2ff < "$TMP" + ;; + image/jpeg) + jpg2ff < "$TMP" + ;; + *) + if [ ! -x /usr/bin/convert ] ; then + printf "%s: cant convert from %s -- missing \`convert' program" "$0" "$FORMAT" >&2 + printf "Run \`apt-get install imagemagick' to install it" >&2 + exit 1 + fi -case "$FORMAT" in -image/png) - png2ff < "$TMP" - ;; -image/jpeg) - jpg2ff < "$TMP" - ;; -*) - if [ ! -x /usr/bin/convert ] ; then - printf "%s: cant convert from %s -- missing \`convert' program" "$0" "$FORMAT" >&2 - printf "Run \`apt-get install imagemagick' to install it" >&2 - exit 1 - fi - convert "$TMP" png:- 2>/dev/null | png2ff 2>/dev/null - ;; -esac + convert "$TMP" png:- | png2ff + ;; + esac +fi +# errors if [ $? -ne 0 ]; then - printf "%s: failed to convert from %s\n" "$0" "$FORMAT" >&2 exit 1 +else + exit 0 fi - -exit 0 @@ -1,4 +1,4 @@ -.Dd 2016-01-05 +.Dd 2017-04-14 .Dt 2FF 1 .Os suckless.org .Sh NAME @@ -13,9 +13,9 @@ reads an image from stdin, converts it to and writes the result to stdout. .Pp .Nm -is a wrapper script around the *2ff-tools -with a soft fallback to obtaining a PNG from imagemagick's -.Xr convert 1 +is a wrapper script around the farbfeld conversion tools +with a fallback to obtaining a PNG using +.Xr ImageMagick 1 and passing it through .Xr png2ff 1 . .Pp @@ -27,9 +27,7 @@ writes a diagnostic message to stderr. .It 0 Image processed successfully. .It 1 -An error occurred or -.Xr convert 1 -was not found in the fallback. +An error occurred. .El .Sh EXAMPLES $ @@ -40,12 +38,8 @@ $ .Nm < image.* | bzip2 > image.ff.bz2 .Sh SEE ALSO -.Xr bunzip2 1 , .Xr bzip2 1 , -.Xr convert 1 , -.Xr ff2png 1 , -.Xr jpg2ff 1 , -.Xr png2ff 1 , +.Xr ImageMagick 1 , .Xr farbfeld 5 .Sh AUTHORS .An Laslo Hunhold Aq Mt dev@frign.de @@ -1,6 +1,6 @@ ISC-License -(c) 2014-2016 Laslo Hunhold <dev@frign.de> +(c) 2014-2017 Laslo Hunhold <dev@frign.de> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -1,52 +1,54 @@ -# farbfeld - suckless image format with conversion tools # See LICENSE file for copyright and license details +# farbfeld - suckless image format with conversion tools +.POSIX: + include config.mk -BIN = png2ff ff2png jpg2ff ff2jpg ff2pam ff2ppm -SCRIPTS = 2ff -SRC = ${BIN:=.c} +REQ = util HDR = arg.h -MAN1 = 2ff.1 ${BIN:=.1} +BIN = png2ff ff2png jpg2ff ff2jpg ff2pam ff2ppm +SCR = 2ff +MAN1 = 2ff.1 $(BIN:=.1) MAN5 = farbfeld.5 -all: ${BIN} +png2ff-LDFLAGS = $(PNG-LDFLAGS) +ff2png-LDFLAGS = $(PNG-LDFLAGS) +jpg2ff-LDFLAGS = $(JPG-LDFLAGS) +ff2jpg-LDFLAGS = $(JPG-LDFLAGS) -${BIN}: ${@:=.o} +all: $(BIN) -OBJ = ${SRC:.c=.o} +$(BIN): $(REQ:=.o) -${OBJ}: config.mk ${HDR} +$(BIN:=.o): config.mk $(HDR) $(REQ:=.h) .o: - ${CC} ${CFLAGS} ${$*-LDFLAGS} -o $@ $< - -.c.o: - ${CC} ${CFLAGS} ${$*-CFLAGS} ${CPPFLAGS} -c $< + $(CC) $(LDFLAGS) $($*-LDFLAGS) -o $@ $< $(REQ:=.o) clean: - rm -f ${BIN} ${OBJ} + rm -f $(BIN) $(BIN:=.o) $(REQ:=.o) dist: - rm -rf "farbfeld-${VERSION}" - mkdir -p "farbfeld-${VERSION}" - cp -R FORMAT LICENSE Makefile README TODO config.mk ${SCRIPTS} ${HDR} ${SRC} ${MAN1} ${MAN5} "farbfeld-${VERSION}" - tar -cf - "farbfeld-${VERSION}" | gzip -c > "farbfeld-${VERSION}.tar.gz" - rm -rf "farbfeld-${VERSION}" + rm -rf "farbfeld-$(VERSION)" + mkdir -p "farbfeld-$(VERSION)" + cp -R FORMAT LICENSE Makefile README config.mk $(SCR) \ + $(HDR) $(BIN:=.c) $(REQ:=.c) $(REQ:=.h) \ + $(MAN1) $(MAN5) "farbfeld-$(VERSION)" + tar -cf - "farbfeld-$(VERSION)" | gzip -c > "farbfeld-$(VERSION).tar.gz" + rm -rf "farbfeld-$(VERSION)" install: all - mkdir -p "${DESTDIR}${PREFIX}/bin" - cp -f ${SCRIPTS} ${BIN} "${DESTDIR}${PREFIX}/bin" - for f in $(BIN) $(SCRIPTS); do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done - mkdir -p "${DESTDIR}${MANPREFIX}/man1" - cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1" - for m in $(MAN1); do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done - mkdir -p "${DESTDIR}${MANPREFIX}/man5" - cp -f ${MAN5} "${DESTDIR}${MANPREFIX}/man5" - for m in $(MAN5); do chmod 644 "${DESTDIR}${MANPREFIX}/man5/$$m"; done + mkdir -p "$(DESTDIR)$(PREFIX)/bin" + cp -f $(SCR) $(BIN) "$(DESTDIR)$(PREFIX)/bin" + for f in $(BIN) $(SCR); do chmod 755 "$(DESTDIR)$(PREFIX)/bin/$$f"; done + mkdir -p "$(DESTDIR)$(MANPREFIX)/man1" + cp -f $(MAN1) "$(DESTDIR)$(MANPREFIX)/man1" + for m in $(MAN1); do chmod 644 "$(DESTDIR)$(MANPREFIX)/man1/$$m"; done + mkdir -p "$(DESTDIR)$(MANPREFIX)/man5" + cp -f $(MAN5) "$(DESTDIR)$(MANPREFIX)/man5" + for m in $(MAN5); do chmod 644 "$(DESTDIR)$(MANPREFIX)/man5/$$m"; done uninstall: - for f in $(BIN) $(SCRIPTS); do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done - for m in $(MAN1); do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done - for m in $(MAN5); do rm -f "${DESTDIR}${MANPREFIX}/man5/$$m"; done - -.PHONY: all clean dist install uninstall + for f in $(BIN) $(SCR); do rm -f "$(DESTDIR)$(PREFIX)/bin/$$f"; done + for m in $(MAN1); do rm -f "$(DESTDIR)$(MANPREFIX)/man1/$$m"; done + for m in $(MAN5); do rm -f "$(DESTDIR)$(MANPREFIX)/man5/$$m"; done @@ -1,16 +1,35 @@ - ███ ███ ██ ██ ███ ███ █ ██ - █ █ █ █ █ █ █ █ █ █ █ █ - ██ ███ ███ ███ ██ ██ █ █ █ - █ █ █ █ █ █ █ █ █ █ █ █ - █ █ █ █ █ ██ █ ███ ███ ██ + ███ ███ ██ ██ ███ ███ █ ██ + █ █ █ █ █ █ █ █ █ █ █ █ + ██ ███ ██ ███ ██ ██ █ █ █ + █ █ █ █ █ █ █ █ █ █ █ █ + █ █ █ █ █ ██ █ ███ ███ ██ WHAT IS FARBFELD? Farbfeld is a lossless image-format designed to be - parsed and piped easily. - It can be compressed easily and beats PNG's filesize + parsed and piped easily. It is probably the simplest + image-format you can find (see FORMAT). + It does not have integrated compression, but allows + compression algorithms to work with it easily by adding + little entropy to the image data itself. This beats PNG in many cases. + Given the free choice of compression algorithms, it + is trivial to switch to better and faster ones as they + show up in the future. + +HOW DO I USE THE TOOLS? + encoding: + png2ff < example.png > example.ff + png2ff < example.png | bzip2 > example.ff.bz2 + + decoding: + ff2png < example.ff > example.png + bzcat example.ff.bz2 | ff2png > example.png + + bzip2 is used in this example and a recommended + compression algorithm. Of course you are free + to use something else. WHY FARBFELD? Current image-formats have integrated compression, @@ -32,13 +51,13 @@ WHY FARBFELD? and farbfeld. HOW DOES IT WORK? - In Farbfeld, pattern resolution is not done while + In farbfeld, pattern resolution is not done while converting, but while compressing the image. For example, farbfeld always stores the alpha-channel, even if the image doesn't have alpha-variation. This may sound like a big waste at first, but as soon as you compress an image of this kind, the - compression-algorithm (e.g. bz2) recognizes the + compression-algorithm (e.g. bzip2) recognizes the pattern that every 48 bits the 16 bits store the same information. And the compression-algorithms get better and better @@ -49,19 +68,7 @@ HOW DOES IT WORK? the same value, which is recognized by the compression algorithm easily. This effectively leads to filesizes you'd normally only - reach with paletted images, and in some cases bz2 even + reach with paletted images, and in some cases bzip2 even beats png's compression, for instance when you're dealing with grayscale data, line drawings, decals and even photographs. - -HOW DO I USE THE TOOLS? - encoding: - png2ff < example.png > example.ff - png2ff < example.png | bzip2 > example.ff.bz2 - - decoding: - ff2png < example.ff > example.png - bzcat example.ff.bz2 | ff2png > example.png - - bz2 is recommended for compression, but you can use - any algorithm you want. @@ -1,3 +0,0 @@ - o re-add the old imagefile-tools for gif, ... - o flush fp's (fflush()) so we correctly report on truncation - o write utility functions to solve duplicate tasks @@ -1,5 +1,5 @@ # farbfeld version -VERSION = 2 +VERSION = 3 # Customize below to fit your system @@ -7,33 +7,12 @@ VERSION = 2 PREFIX = /usr MANPREFIX = ${PREFIX}/share/man -PNGLIB = /usr/local/lib -PNGINC = /usr/local/include - -JPGLIB = /usr/local/lib -JPGINC = /usr/local/include - -INCS = -LIBS = - # flags CPPFLAGS += -D_DEFAULT_SOURCE -CFLAGS += -std=c99 -pedantic -Wall -Os ${INCS} -LDFLAGS += -s ${LIBS} +CFLAGS += -std=c99 -pedantic -Wall -Wextra -Os +LDFLAGS += -s +PNG-LDFLAGS = -lpng +JPG-LDFLAGS = -ljpeg # compiler and linker CC = cc - -# flags per tool. - -png2ff-CFLAGS := -I${PNGINC} -png2ff-LDFLAGS := -L${PNGLIB} -lpng - -ff2png-CFLAGS := -I${PNGINC} -ff2png-LDFLAGS := -L${PNGLIB} -lpng - -jpg2ff-CFLAGS := -I${JPGINC} -jpg2ff-LDFLAGS := -L${JPGLIB} -ljpeg - -ff2jpg-CFLAGS := -I${JPGINC} -ff2jpg-LDFLAGS := -L${JPGLIB} -ljpeg @@ -1,4 +1,4 @@ -.Dd 2016-01-04 +.Dd 2017-04-14 .Dt FARBFELD 5 .Os suckless.org .Sh NAME @@ -17,17 +17,24 @@ BYTES DESCRIPTION 4 32-Bit BE unsigned integer (height) [2222] 4*16-Bit BE unsigned integers [RGBA] / pixel, row-major .Ed +.Pp The RGB-data should be sRGB for best interoperability and not alpha-premultiplied. .Sh USAGE .Nm -provides -.Xr png2ff 1 , -.Xr jpg2ff 1 , +provides the tools .Xr 2ff 1 , -.Xr ff2png 1 -for -.Em conversions ; +.Xr jpg2ff 1 , +.Xr png2ff 1 +and +.Xr ff2jpg 1 , +.Xr ff2pam 1 , +.Xr ff2png 1 , +.Xr ff2ppm 1 +to +.Em convert +to and from farbfeld images respectively. +.Pp .Xr bzip2 1 is recommended for .Em compression , @@ -42,81 +49,128 @@ appended (e.g. ".ff.bz2"). .Nm was created because the author was not satisfied with the boilerplate and inherent complexity involved in handling common image formats -(PNG, JPEG, GIF,...), having to rely on bloated libraries not being able -to focus on the task at hand for a given problem. +(PNG, JPEG, GIF,...), having to rely on bloated libraries while not being +able to focus on the task at hand for a given image processing problem. .Sh EXAMPLES -Below is an example for a color inverter usable in a pipeline. No external -libraries other than libc are needed to handle the image data: +The following code listing +.Em invert.c +is a ready-to-use color inverter with all necessary error handling and +reporting. This program can be integrated into a farbfeld pipeline as +follows: +.Pp +$ png2ff < image.png | invert | ff2png > image-inverted.png +.Pp +It shall be noted here that due to the simplicity of the format no +external libraries are needed to handle the farbfeld image data. The +0BSD-License gives you the freedom to throw away the license block and +just use the code as you wish. Happy hacking! .Bd -literal -offset left +/* + * 0BSD-License + * + * (c) 2017 Laslo Hunhold <dev@frign.de> + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ #include <arpa/inet.h> +#include <errno.h> #include <stdint.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> +#define LEN(x) (sizeof (x) / sizeof *(x)) + +static void +invert(uint16_t rgba[4]) +{ + rgba[0] = UINT16_MAX - rgba[0]; + rgba[1] = UINT16_MAX - rgba[1]; + rgba[2] = UINT16_MAX - rgba[2]; +} + int main(int argc, char *argv[]) { - uint32_t width, height, i, j, k; + uint32_t hdr[4], width, height, i, j, k; uint16_t rgba[4]; - uint8_t hdr[strlen("farbfeld") + 2 * sizeof(uint32_t)]; - if (argc > 1) { + /* arguments */ + if (argc != 1) { fprintf(stderr, "usage: %s\\n", argv[0]); return 1; } - if (fread(hdr, 1, sizeof(hdr), stdin) != sizeof(hdr)) { - fprintf(stderr, "incomplete header\\n"); - return 1; + /* read header */ + if (fread(hdr, sizeof(*hdr), LEN(hdr), stdin) != LEN(hdr)) { + goto readerr; } - if (memcmp("farbfeld", hdr, strlen("farbfeld"))) { - fprintf(stderr, "invalid magic\\n"); + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { + fprintf(stderr, "%s: invalid magic value\\n", argv[0]); return 1; } - width = ntohl(*((uint32_t *)(hdr + 8))); - height = ntohl(*((uint32_t *)(hdr + 12))); + width = ntohl(hdr[2]); + height = ntohl(hdr[3]); - if (fwrite(hdr, 1, sizeof(hdr), stdout) != sizeof(hdr)) { - fprintf(stderr, "write error\\n"); - return 1; + /* write data */ + if (fwrite(hdr, sizeof(*hdr), LEN(hdr), stdout) != 4) { + goto writerr; } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { - if (fread(rgba, sizeof(uint16_t), 4, - stdin) != 4) { - fprintf(stderr, "unexpected EOF\\n"); - return 1; + if (fread(rgba, sizeof(*rgba), LEN(rgba), + stdin) != LEN(rgba)) { + goto readerr; } for (k = 0; k < 4; k++) { rgba[k] = ntohs(rgba[k]); } - /* invert colors */ - rgba[0] = 65535 - rgba[0]; - rgba[1] = 65535 - rgba[1]; - rgba[2] = 65535 - rgba[2]; + invert(rgba); for (k = 0; k < 4; k++) { rgba[k] = htons(rgba[k]); } - if (fwrite(rgba, sizeof(uint16_t), 4, - stdout) != 4) { - fprintf(stderr, "write error\\n"); - return 1; + if (fwrite(rgba, sizeof(*rgba), LEN(rgba), + stdout) != LEN(rgba)) { + goto writerr; } } } + /* clean up */ + if (fclose(stdout)) { + fprintf(stderr, "%s: fclose: %s\\n", argv[0], + strerror(errno)); + return 1; + } + return 0; +readerr: + fprintf(stderr, "%s: fread: Unexpected EOF\\n", argv[0]); + return 1; +writerr: + fprintf(stderr, "%s: fwrite: %s\\n", argv[0], strerror(errno)); + return 1; } .Ed .Sh SEE ALSO .Xr 2ff 1 , -.Xr bzip2 1 , +.Xr ff2jpg 1 , +.Xr ff2pam 1 , .Xr ff2png 1 , +.Xr ff2ppm 1 , .Xr jpg2ff 1 , .Xr png2ff 1 .Sh AUTHORS @@ -1,19 +1,19 @@ -.Dd 2016-03-23 +.Dd 2017-04-14 .Dt FF2JPG 1 .Os suckless.org .Sh NAME .Nm ff2jpg -.Nd convert farbfeld to JPEG +.Nd convert farbfeld to JPG .Sh SYNOPSIS .Nm -.Op Fl b Ar color +.Op Fl b Ar colour .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 +image from stdin, converts it to JPG (8-bit RGB) and writes the result to stdout. .Pp In case of an error @@ -21,18 +21,16 @@ In case of an error 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 b Ar colour +Blend the transparent colours with +.Ar colour +specified as rgb, rrggbb or rrrrggggbbbb. The default is fff. .It Fl o -Optimize Huffman table (smaller file, but slow compression). +Optimize the Huffman table, which reduces the file size but takes longer. .It Fl q Ar quality -set JPEG output +Set the output .Ar quality -(range 0-100), the default is 85. +ranging from 0 to 100. The default is 85. .El .Sh EXIT STATUS .Bl -tag -width Ds @@ -43,14 +41,14 @@ An error occurred. .El .Sh EXAMPLES $ -png2ff < test.png | .Nm --b '#00ff00' -q 85 > test.jpg +< image.ff > image.jpg +.Pp +$ bunzip2 < image.ff.bz2 | +.Nm +-b 0f0 -q 90 > image.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 @@ -11,10 +11,9 @@ #include <jpeglib.h> #include "arg.h" +#include "util.h" -char *argv0; - -METHODDEF(void) +static void jpeg_error(j_common_ptr js) { fprintf(stderr, "%s: libjpeg: ", argv0); @@ -23,129 +22,103 @@ jpeg_error(j_common_ptr js) } static void +jpeg_setup_writer(struct jpeg_compress_struct *s, struct jpeg_error_mgr *e, + uint32_t w, uint32_t h, int quality, int opt) +{ + jpeg_create_compress(s); + e->error_exit = jpeg_error; + s->err = jpeg_std_error(e); + + jpeg_stdio_dest(s, stdout); + s->image_width = w; + s->image_height = h; + s->input_components = 3; /* color components per pixel */ + s->in_color_space = JCS_RGB; /* output color space */ + jpeg_set_defaults(s); + + if (opt) { + s->optimize_coding = 1; + } + jpeg_set_quality(s, quality, 1); + + jpeg_start_compress(s, 1); +} + +static void usage(void) { - fprintf(stderr, "usage: %s [-b #rrggbb] [-o] [-q quality]\n", argv0); + fprintf(stderr, "usage: %s [-b colour] [-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_compress_struct jcomp; struct jpeg_error_mgr jerr; size_t rowlen; uint64_t a; - uint32_t hdr[4], width, height, i, j, k, l; + uint32_t 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; + int optimize = 0, quality = 85; - argv0 = argv[0]; + /* arguments */ ARGBEGIN { case 'b': - color = EARGF(usage()); - if (color[0] == '#') { - color++; - } - collen = strlen(color); - if (collen != 3 && collen != 6 && collen != 12) { + if (parse_mask(EARGF(usage()), mask)) { 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(); + quality = estrtonum(EARGF(usage()), 0, 100); break; default: usage(); } ARGEND - if (argc) + if (argc) { usage(); - - /* header */ - if (fread(hdr, sizeof(*hdr), 4, stdin) != 4) { - goto readerr; - } - if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { - fprintf(stderr, "%s: invalid magic value\n", argv0); - return 1; } - width = ntohl(hdr[2]); - height = ntohl(hdr[3]); - if (width > SIZE_MAX / ((sizeof("RGBA") - 1) * sizeof(uint16_t))) { - fprintf(stderr, "%s: row length integer overflow\n", argv0); - return 1; - } + /* prepare */ + ff_read_header(&width, &height); + jpeg_setup_writer(&jcomp, &jerr, width, height, quality, optimize); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); 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; + rowout = ereallocarray(NULL, width, (sizeof("RGB") - 1) * sizeof(uint8_t)); - 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 */ + /* write data */ for (i = 0; i < height; ++i) { if (fread(row, sizeof(uint16_t), rowlen, stdin) != rowlen) { - goto readerr; + if (ferror(stdin)) { + fprintf(stderr, "%s: fread: %s\n", argv0, + strerror(errno)); + } else { + fprintf(stderr, "%s: unexpected end of file\n", + argv0); + } + return 1; } for (j = 0, k = 0; j < rowlen; j += 4, k += 3) { a = ntohs(row[j + 3]); for (l = 0; l < 3; l++) { + /* alpha blending and 8-bit-reduction */ rowout[k + l] = (a * ntohs(row[j + l]) + - (65535 - a) * mask[l]) / - (257 * 65535); + (UINT16_MAX - a) * mask[l]) / + (UINT16_MAX * + (UINT16_MAX / UINT8_MAX)); } } - jpeg_write_scanlines(&cinfo, row_pointer, 1); + jpeg_write_scanlines(&jcomp, &rowout, 1); } - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - return 0; -readerr: - if (ferror(stdin)) { - fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); - } else { - fprintf(stderr, "%s: unexpected end of file\n", argv0); - } + /* clean up */ + jpeg_finish_compress(&jcomp); + jpeg_destroy_compress(&jcomp); - return 1; + return fshut(stdout, "<stdout>"); } @@ -1,4 +1,4 @@ -.Dd 2017-01-09 +.Dd 2017-04-14 .Dt FF2PAM 1 .Os suckless.org .Sh NAME @@ -10,7 +10,7 @@ .Nm reads a .Xr farbfeld 5 -image from stdin, converts it to a 16-bit RGBA PAM and writes the result +image from stdin, converts it to PAM (16-bit RGBA) and writes the result to stdout. .Pp In case of an error @@ -32,10 +32,7 @@ $ bunzip2 < image.ff.bz2 | .Nm > image.pam .Sh SEE ALSO -.Xr 2ff 1 , -.Xr bunzip2 1 , .Xr bzip2 1 , -.Xr png2ff 1 , .Xr farbfeld 5 .Sh AUTHORS .An Mattias Andrée Aq Mt maandree@kth.se @@ -5,38 +5,39 @@ #include <inttypes.h> #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> -static char *argv0; +#include "util.h" + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", argv0); + exit(1); +} int main(int argc, char *argv[]) { - uint32_t hdr[4], width, height; - char buf[BUFSIZ]; - size_t n, t; + size_t rowlen; + uint32_t width, height, i; + uint16_t *row; + /* arguments */ argv0 = argv[0], argc--, argv++; if (argc) { - fprintf(stderr, "usage: %s\n", argv0); - return 1; + usage(); } - /* header */ - if (fread(hdr, sizeof(*hdr), 4, stdin) != 4) { - fprintf(stderr, "%s: file too short\n", argv0); - return 1; - } - if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { - fprintf(stderr, "%s: invalid magic value\n", argv0); - return 1; - } - width = ntohl(hdr[2]); - height = ntohl(hdr[3]); + /* prepare */ + ff_read_header(&width, &height); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); + rowlen = width * (sizeof("RGBA") - 1); - /* write header */ + /* write data */ printf("P7\n" "WIDTH %" PRIu32 "\n" "HEIGHT %" PRIu32 "\n" @@ -46,29 +47,20 @@ main(int argc, char *argv[]) "ENDHDR\n", width, height); - /* write image */ - t = (size_t)width * (size_t)height * sizeof(uint16_t) * (sizeof("RGBA") - 1); - for (; (n = fread(buf, 1, sizeof(buf) <= t ? sizeof(buf) : t, stdin)); ) { - t -= n; - fwrite(buf, 1, n, stdout); - - if (feof(stdin)) { - break; - } - if (ferror(stdin)) { - fprintf(stderr, "%s: read: %s\n", argv0, strerror(errno)); + for (i = 0; i < height; i++) { + if (fread(row, sizeof(uint16_t), rowlen, stdin) != rowlen) { + if (ferror(stdin)) { + fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); + } else { + fprintf(stderr, "%s: unexpected end of file\n", argv0); + } return 1; } - if (ferror(stdout)) { - fprintf(stderr, "%s: write: %s\n", argv0, strerror(errno)); + if (fwrite(row, sizeof(uint16_t), rowlen, stdout) != rowlen) { + fprintf(stderr, "%s: fwrite: %s\n", argv0, strerror(errno)); return 1; } } - if (t > 0) { - fprintf(stderr, "%s: file too short\n", argv0); - return 1; - } - - return 0; + return fshut(stdout, "<stdout>"); } @@ -1,4 +1,4 @@ -.Dd 2016-01-17 +.Dd 2017-04-14 .Dt FF2PNG 1 .Os suckless.org .Sh NAME @@ -10,7 +10,7 @@ .Nm reads a .Xr farbfeld 5 -image from stdin, converts it to a 16-Bit RGBA PNG and writes the result +image from stdin, converts it to PNG (16-bit RGBA) and writes the result to stdout. .Pp In case of an error @@ -32,11 +32,7 @@ $ bunzip2 < image.ff.bz2 | .Nm > image.png .Sh SEE ALSO -.Xr 2ff 1 , -.Xr bunzip2 1 , .Xr bzip2 1 , -.Xr jpg2ff 1 , -.Xr png2ff 1 , .Xr farbfeld 5 .Sh AUTHORS .An Laslo Hunhold Aq Mt dev@frign.de @@ -9,83 +9,79 @@ #include <png.h> -static char *argv0; +#include "util.h" -void -pngerr(png_structp pngs, const char *msg) +static void +png_err(png_struct *pngs, const char *msg) { + (void)pngs; fprintf(stderr, "%s: libpng: %s\n", argv0, msg); exit(1); } +static void +png_setup_writer(png_struct **s, png_info **i, uint32_t w, uint32_t h) +{ + *s = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_err, NULL); + *i = png_create_info_struct(*s); + + if (!*s || !*i) { + fprintf(stderr, "%s: failed to initialize libpng\n", argv0); + exit(1); + } + + png_init_io(*s, stdout); + png_set_IHDR(*s, *i, w, h, 16, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + png_write_info(*s, *i); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", argv0); + exit(1); +} + int main(int argc, char *argv[]) { - png_structp pngs; - png_infop pngi; + png_struct *pngs; + png_info *pngi; size_t rowlen; - uint32_t hdr[4], width, height, i; + uint32_t width, height, i; uint16_t *row; + /* arguments */ argv0 = argv[0], argc--, argv++; if (argc) { - fprintf(stderr, "usage: %s\n", argv0); - return 1; - } - - /* header */ - if (fread(hdr, sizeof(*hdr), 4, stdin) != 4) { - goto readerr; - } - if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { - fprintf(stderr, "%s: invalid magic value\n", argv0); - return 1; + usage(); } - width = ntohl(hdr[2]); - height = ntohl(hdr[3]); - - /* load png */ - pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngerr, - NULL); - pngi = png_create_info_struct(pngs); - - if (!pngs || !pngi) { - fprintf(stderr, "%s: failed to initialize libpng\n", argv0); - return 1; - } - png_init_io(pngs, stdout); - png_set_IHDR(pngs, pngi, width, height, 16, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - png_write_info(pngs, pngi); - /* write rows */ - if (width > SIZE_MAX / ((sizeof("RGBA") - 1) * sizeof(uint16_t))) { - fprintf(stderr, "%s: row length integer overflow\n", argv0); - return 1; - } + /* prepare */ + ff_read_header(&width, &height); + png_setup_writer(&pngs, &pngi, width, height); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); rowlen = width * (sizeof("RGBA") - 1); - if (!(row = malloc(rowlen * sizeof(uint16_t)))) { - fprintf(stderr, "%s: malloc: out of memory\n", argv0); - return 1; - } + + /* write data */ for (i = 0; i < height; ++i) { if (fread(row, sizeof(uint16_t), rowlen, stdin) != rowlen) { - goto readerr; + if (ferror(stdin)) { + fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); + } else { + fprintf(stderr, "%s: unexpected end of file\n", argv0); + } + return 1; } png_write_row(pngs, (uint8_t *)row); } + + /* clean up */ png_write_end(pngs, NULL); png_destroy_write_struct(&pngs, NULL); - return 0; -readerr: - if (ferror(stdin)) { - fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); - } else { - fprintf(stderr, "%s: unexpected end of file\n", argv0); - } - - return 1; + return fshut(stdout, "<stdout>"); } @@ -1,17 +1,17 @@ -.Dd 2016-03-21 +.Dd 2017-04-14 .Dt FF2PPM 1 .Os suckless.org .Sh NAME .Nm ff2ppm -.Nd convert farbfeld to PPM (binary) +.Nd convert farbfeld to PPM .Sh SYNOPSIS .Nm -.Op Fl b Ar color +.Op Fl b Ar colour .Sh DESCRIPTION .Nm reads a .Xr farbfeld 5 -image from stdin, converts it to a PPM image (P6 binary format, RGB) and +image from stdin, converts it to PPM (16-Bit RGB P6 binary format) and writes the result to stdout. .Pp In case of an error @@ -19,12 +19,10 @@ In case of an error 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 b Ar colour +Blend the transparent colours with +.Ar colour +specified as rgb, rrggbb or rrrrggggbbbb. The default is fff. .El .Sh EXIT STATUS .Bl -tag -width Ds @@ -35,14 +33,14 @@ An error occurred. .El .Sh EXAMPLES $ -png2ff < test.png | .Nm --b '#00ff00' > test.ppm +< image.ff > image.ppm +.Pp +$ bunzip2 < image.ff.bz2 | +.Nm +-b 0f0 > image.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 @@ -9,109 +9,75 @@ #include <string.h> #include "arg.h" - -char *argv0; +#include "util.h" static void usage(void) { - fprintf(stderr, "usage: %s [-b #rrggbb]\n", argv0); + fprintf(stderr, "usage: %s [-b colour]\n", argv0); exit(1); } int main(int argc, char *argv[]) { - size_t rowlen; + size_t rowlen, rowoutlen; uint64_t a; - uint32_t hdr[4], width, height, i, j, k, l; + uint32_t 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; - argv0 = argv[0]; + /* arguments */ 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) { + if (parse_mask(EARGF(usage()), mask)) { 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; default: usage(); } ARGEND - if (argc) + if (argc) { usage(); - - /* header */ - if (fread(hdr, sizeof(*hdr), 4, stdin) != 4) { - goto readerr; - } - if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { - fprintf(stderr, "%s: invalid magic value\n", argv0); - return 1; } - width = ntohl(hdr[2]); - height = ntohl(hdr[3]); - if (width > SIZE_MAX / ((sizeof("RGBA") - 1) * sizeof(uint16_t))) { - fprintf(stderr, "%s: row length integer overflow\n", argv0); - return 1; - } + /* prepare */ + ff_read_header(&width, &height); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); + rowout = ereallocarray(NULL, width, (sizeof("RGB") - 1) * sizeof(uint8_t)); 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; - } + rowoutlen = width * (sizeof("RGB") - 1); - /* PPM binary */ + /* write data */ 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) { - goto readerr; + if (ferror(stdin)) { + fprintf(stderr, "%s: fread: %s\n", argv0, + strerror(errno)); + } else { + fprintf(stderr, "%s: unexpected end of file\n", + argv0); + } + return 1; } for (j = 0, k = 0; j < rowlen; j += 4, k += 3) { a = ntohs(row[j + 3]); for (l = 0; l < 3; l++) { + /* alpha blending and 8-bit-reduction */ rowout[k + l] = (a * ntohs(row[j + l]) + - (65535 - a) * mask[l]) / - (257 * 65535); + (UINT16_MAX - a) * mask[l]) / + (UINT16_MAX * + (UINT16_MAX / UINT8_MAX)); } } - if (fwrite(rowout, 3, width, stdout) != width) { + if (fwrite(rowout, sizeof(uint8_t), rowoutlen, stdout) != rowoutlen) { fprintf(stderr, "%s: fwrite: %s\n", argv0, strerror(errno)); return 1; } } - return 0; -readerr: - if (ferror(stdin)) { - fprintf(stderr, "%s: fread: %s\n", argv0, strerror(errno)); - } else { - fprintf(stderr, "%s: unexpected end of file\n", argv0); - } - - return 1; + return fshut(stdout, "<stdout>"); } @@ -1,4 +1,4 @@ -.Dd 2016-01-19 +.Dd 2017-04-14 .Dt JPG2FF 1 .Os suckless.org .Sh NAME @@ -32,10 +32,7 @@ $ < image.jpg | bzip2 > image.ff.bz2 .Sh SEE ALSO .Xr 2ff 1 , -.Xr bunzip2 1 , .Xr bzip2 1 , -.Xr ff2png 1 , -.Xr png2ff 1 , .Xr farbfeld 5 .Sh AUTHORS .An Laslo Hunhold Aq Mt dev@frign.de @@ -5,12 +5,13 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <jpeglib.h> -static char *argv0; +#include "util.h" -METHODDEF(void) +static void jpeg_error(j_common_ptr js) { fprintf(stderr, "%s: libjpeg: ", argv0); @@ -18,86 +19,76 @@ jpeg_error(j_common_ptr js) exit(1); } +static void +jpeg_setup_reader(struct jpeg_decompress_struct *s, struct jpeg_error_mgr *e, + uint32_t *w, uint32_t *h) +{ + jpeg_create_decompress(s); + e->error_exit = jpeg_error; + s->err = jpeg_std_error(e); + + jpeg_stdio_src(s, stdin); + jpeg_read_header(s, 1); + *w = s->image_width; + *h = s->image_height; + s->output_components = 3; /* color components per pixel */ + s->out_color_space = JCS_RGB; /* input color space */ + + jpeg_start_decompress(s); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", argv0); + exit(1); +} + int main(int argc, char *argv[]) { struct jpeg_decompress_struct js; struct jpeg_error_mgr jerr; - uint32_t width, height, tmp32; + uint32_t width, height; uint16_t *row; + uint8_t *rowin; size_t rowlen, i; - JSAMPARRAY jpgrow; + /* arguments */ argv0 = argv[0], argc--, argv++; if (argc) { - fprintf(stderr, "usage: %s\n", argv0); - return 1; + usage(); } - /* load jpg */ - js.err = jpeg_std_error(&jerr); - jerr.error_exit = jpeg_error; - - jpeg_create_decompress(&js); - - jpeg_stdio_src(&js, stdin); - - jpeg_read_header(&js, 1); - width = js.image_width; - height = js.image_height; - - /* set output format */ - js.output_components = 3; /* color components per pixel */ - js.out_color_space = JCS_RGB; /* input color space */ - - jpeg_start_decompress(&js); - - /* create output buffers */ - jpgrow = (*js.mem->alloc_sarray)((j_common_ptr)&js, - JPOOL_IMAGE, width * - js.output_components, 1); + /* prepare */ + jpeg_setup_reader(&js, &jerr, &width, &height); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); rowlen = width * (sizeof("RGBA") - 1); - if(!(row = malloc(rowlen * sizeof(uint16_t)))) { - fprintf(stderr, "%s: malloc: out of memory\n", argv0); - return 1; - } + rowin = ereallocarray(NULL, width, (sizeof("RGB") - 1) * sizeof(uint8_t)); - /* write header */ - fputs("farbfeld", stdout); - tmp32 = htonl(width); - if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1) - goto writerr; - tmp32 = htonl(height); - if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1) - goto writerr; + /* write data */ + ff_write_header(width, height); while (js.output_scanline < js.output_height) { - /* jpeg_read_scanlines expects an array of pointers to - * scanlines. - * Here the array is only one element long, but you could - * ask for more than one scanline at a time if that's more - * convenient. */ - jpeg_read_scanlines(&js, jpgrow, 1); + jpeg_read_scanlines(&js, &rowin, 1); for (i = 0; i < width; ++i) { - row[4*i + 0] = htons(jpgrow[0][3*i + 0] * 257); - row[4*i + 1] = htons(jpgrow[0][3*i + 1] * 257); - row[4*i + 2] = htons(jpgrow[0][3*i + 2] * 257); - row[4*i + 3] = htons(65535); + row[4 * i + 0] = htons(rowin[3 * i + 0] * 257); + row[4 * i + 1] = htons(rowin[3 * i + 1] * 257); + row[4 * i + 2] = htons(rowin[3 * i + 2] * 257); + row[4 * i + 3] = htons(65535); } - /* write data */ - if (fwrite(row, sizeof(uint16_t), rowlen, stdout) != rowlen) - goto writerr; + if (fwrite(row, sizeof(uint16_t), rowlen, stdout) != rowlen) { + fprintf(stderr, "%s: fwrite: %s\n", argv0, strerror(errno)); + return 1; + } } + + /* clean up */ jpeg_finish_decompress(&js); jpeg_destroy_decompress(&js); - return 0; -writerr: - fprintf(stderr, "%s: fwrite: ", argv0); - perror(NULL); - - return 1; + return fshut(stdout, "<stdout>"); } @@ -1,4 +1,4 @@ -.Dd 2016-01-19 +.Dd 2017-04-14 .Dt PNG2FF 1 .Os suckless.org .Sh NAME @@ -32,10 +32,7 @@ $ < image.png | bzip2 > image.ff.bz2 .Sh SEE ALSO .Xr 2ff 1 , -.Xr bunzip2 1 , .Xr bzip2 1 , -.Xr ff2png 1 , -.Xr jpg2ff 1 , .Xr farbfeld 5 .Sh AUTHORS .An Laslo Hunhold Aq Mt dev@frign.de @@ -5,77 +5,76 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <png.h> -static char *argv0; +#include "util.h" -void -pngerr(png_structp pngs, const char *msg) +static void +png_err(png_struct *pngs, const char *msg) { + (void)pngs; fprintf(stderr, "%s: libpng: %s\n", argv0, msg); exit(1); } +static void +png_setup_reader(png_struct **s, png_info **i, uint32_t *w, uint32_t *h) +{ + *s = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_err, NULL); + *i = png_create_info_struct(*s); + + if (!*s || !*i) { + fprintf(stderr, "%s: failed to initialize libpng\n", argv0); + exit(1); + } + + png_init_io(*s, stdin); + if (png_get_valid(*s, *i, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(*s); + } + png_set_add_alpha(*s, 255*257, PNG_FILLER_AFTER); + png_set_expand_gray_1_2_4_to_8(*s); + png_set_gray_to_rgb(*s); + png_set_packing(*s); + png_read_png(*s, *i, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); + *w = png_get_image_width(*s, *i); + *h = png_get_image_height(*s, *i); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", argv0); + exit(1); +} + int main(int argc, char *argv[]) { - png_structp pngs; - png_infop pngi; - uint32_t width, height, rowlen, tmp32, r, i; + png_struct *pngs; + png_info *pngi; + uint32_t width, height, rowlen, r, i; uint16_t *row; uint8_t **pngrows; + /* arguments */ argv0 = argv[0], argc--, argv++; if (argc) { - fprintf(stderr, "usage: %s\n", argv0); - return 1; + usage(); } - /* load png */ - pngs = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngerr, - NULL); - pngi = png_create_info_struct(pngs); - - if (!pngs || !pngi) { - fprintf(stderr, "%s: failed to initialize libpng\n", argv0); - return 1; - } - png_init_io(pngs, stdin); - if (png_get_valid(pngs, pngi, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(pngs); - png_set_add_alpha(pngs, 255*257, PNG_FILLER_AFTER); - png_set_expand_gray_1_2_4_to_8(pngs); - png_set_gray_to_rgb(pngs); - png_set_packing(pngs); - png_read_png(pngs, pngi, PNG_TRANSFORM_PACKING | - PNG_TRANSFORM_EXPAND, NULL); - width = png_get_image_width(pngs, pngi); - height = png_get_image_height(pngs, pngi); - pngrows = png_get_rows(pngs, pngi); - - /* allocate output row buffer */ - if (width > SIZE_MAX / ((sizeof("RGBA") - 1) * sizeof(uint16_t))) { - fprintf(stderr, "%s: row length integer overflow\n", argv0); - return 1; - } + /* prepare */ + png_setup_reader(&pngs, &pngi, &width, &height); + row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t)); rowlen = width * (sizeof("RGBA") - 1); - if (!(row = malloc(rowlen * sizeof(uint16_t)))) { - fprintf(stderr, "%s: malloc: out of memory\n", argv0); - return 1; - } - - /* write header */ - fputs("farbfeld", stdout); - tmp32 = htonl(width); - if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1) - goto writerr; - tmp32 = htonl(height); - if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1) - goto writerr; + pngrows = png_get_rows(pngs, pngi); /* write data */ + ff_write_header(width, height); + switch(png_get_bit_depth(pngs, pngi)) { case 8: for (r = 0; r < height; ++r) { @@ -84,7 +83,9 @@ main(int argc, char *argv[]) } if (fwrite(row, sizeof(uint16_t), rowlen, stdout) != rowlen) { - goto writerr; + fprintf(stderr, "%s: fwrite: %s\n", argv0, + strerror(errno)); + return 1; } } break; @@ -92,7 +93,9 @@ main(int argc, char *argv[]) for (r = 0; r < height; ++r) { if (fwrite(pngrows[r], sizeof(uint16_t), rowlen, stdout) != rowlen) { - goto writerr; + fprintf(stderr, "%s: fwrite: %s\n", argv0, + strerror(errno)); + return 1; } } break; @@ -101,12 +104,8 @@ main(int argc, char *argv[]) return 1; } + /* clean up */ png_destroy_read_struct(&pngs, &pngi, NULL); - return 0; -writerr: - fprintf(stderr, "%s: fwrite: ", argv0); - perror(NULL); - - return 1; + return fshut(stdout, "<stdout>"); } @@ -0,0 +1,238 @@ +/* See LICENSE file for copyright and license details. */ +#include <arpa/inet.h> + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +char *argv0; + +void +ff_read_header(uint32_t *width, uint32_t *height) +{ + uint32_t hdr[4]; + + if (fread(hdr, sizeof(*hdr), LEN(hdr), stdin) != LEN(hdr)) { + fprintf(stderr, "%s: fread: %s", argv0, strerror(errno)); + exit(1); + } + + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { + fprintf(stderr, "%s: invalid magic value\n", argv0); + exit(1); + } + + *width = ntohl(hdr[2]); + *height = ntohl(hdr[3]); +} + +void +ff_write_header(uint32_t width, uint32_t height) +{ + uint32_t tmp; + + fputs("farbfeld", stdout); + + tmp = htonl(width); + if (fwrite(&tmp, sizeof(tmp), 1, stdout) != 1) { + fprintf(stderr, "%s: write: %s", argv0, strerror(errno)); + exit(1); + } + + tmp = htonl(height); + if (fwrite(&tmp, sizeof(tmp), 1, stdout) != 1) { + fprintf(stderr, "%s: write: %s", argv0, strerror(errno)); + exit(1); + } +} + +int +parse_mask(const char *s, uint16_t mask[3]) +{ + size_t slen, i; + unsigned int col[3], colfac; + char fmt[] = "%#x%#x%#x"; + + slen = strlen(s); + if (slen != 3 && slen != 6 && slen != 12) { + return 1; + } + + fmt[1] = fmt[4] = fmt[7] = ((slen / 3) + '0'); + if (sscanf(s, fmt, col, col + 1, col + 2) != 3) { + return 1; + } + + colfac = (slen == 3) ? UINT16_MAX / 0xf : + (slen == 6) ? UINT16_MAX / 0xff : + UINT16_MAX / 0xffff; + + for (i = 0; i < 3; i++) { + mask[i] = col[i] * colfac; + } + + return 0; +} + +int +fshut(FILE *fp, const char *fname) +{ + int ret = 0; + + /* fflush() is undefined for input streams by ISO C, + * but not POSIX 2008 if you ignore ISO C overrides. + * Leave it unchecked and rely on the following + * functions to detect errors. + */ + fflush(fp); + + if (ferror(fp) && !ret) { + fprintf(stderr, "%s: ferror %s: %s\n", argv0, fname, + strerror(errno)); + ret = 1; + } + + if (fclose(fp) && !ret) { + fprintf(stderr, "%s: fclose %s: %s\n", argv0, fname, + strerror(errno)); + ret = 1; + } + + return ret; +} + +void * +ereallocarray(void *optr, size_t nmemb, size_t size) +{ + void *p; + + if (!(p = reallocarray(optr, nmemb, size))) { + fprintf(stderr, "%s: reallocarray: out of memory\n", argv0); + exit(1); + } + + return p; +} + +long long +estrtonum(const char *numstr, long long minval, long long maxval) +{ + const char *errstr; + long long ll; + + ll = strtonum(numstr, minval, maxval, &errstr); + if (errstr) { + fprintf(stderr, "%s: strtonum %s: %s\n", argv0, numstr, errstr); + exit(1); + } + + return ll; +} + +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} + +/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} @@ -0,0 +1,22 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdint.h> +#include <stdio.h> + +extern char *argv0; + +#define LEN(x) (sizeof (x) / sizeof *(x)) + +void ff_read_header(uint32_t *width, uint32_t *height); +void ff_write_header(uint32_t width, uint32_t height); + +int parse_mask(const char *, uint16_t mask[3]); + +int fshut(FILE *, const char *); + +#undef reallocarray +void *reallocarray(void *, size_t, size_t); +void *ereallocarray(void *optr, size_t nmemb, size_t size); + +#undef strtonum +long long strtonum(const char *, long long, long long, const char **); +long long estrtonum(const char *, long long, long long); |