farbfeld

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

commit d5f6f70d351239ee37b3d864c9a94dc49d66c052
parent 0b0fcaa7136d7de2e1bc5dc05a576f5fe5608995
Author: FRIGN <dev@frign.de>
Date:   Mon,  9 Nov 2015 23:39:29 +0100

imagefile -> farbfeld

 - Rename the format
 - Change the format specification
 - Drop old tools waiting to be fixed on a later date, just keep
   fixed png for now
 - Simplify other stuff

This is a direct consequence of my slcon2-talk on this topic.
At first I planned to have 64 bits per channel, but this is
overkill.

Diffstat:
MLICENSE | 2+-
MMakefile | 40++++++++++++++--------------------------
MSPECIFICATION | 32+++++++++++++++++++-------------
ATODO | 3+++
Mconfig.mk | 2+-
Aff2png.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dgif2if.c | 177-------------------------------------------------------------------------------
Dif2png.c | 87-------------------------------------------------------------------------------
Djpg2if.c | 121-------------------------------------------------------------------------------
Apng2ff.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dpng2if.c | 77-----------------------------------------------------------------------------
11 files changed, 203 insertions(+), 503 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,6 +1,6 @@ ISC-License -(c) 2014 Laslo Hunhold <dev@frign.de> +(c) 2014-2015 Laslo Hunhold <dev@frign.de> (c) 2014 sin <sin@2f30.org> (c) 2014 Hiltjo Posthuma <hiltjo@codemadness.org> diff --git a/Makefile b/Makefile @@ -1,15 +1,15 @@ -# imagefile - tools to convert between png and if +# imagefile - tools to convert between png and ff # See LICENSE file for copyright and license details include config.mk -SRC = png2if.c if2png.c jpg2if.c gif2if.c +SRC = png2ff.c ff2png.c OBJ = ${SRC:.c=.o} -all: options png2if if2png jpg2if gif2if +all: options png2ff ff2png options: - @echo imagefile build options: + @echo farbfeld build options: @echo "CFLAGS = ${CFLAGS}" @echo "LDFLAGS = ${LDFLAGS}" @echo "CC = ${CC}" @@ -20,40 +20,28 @@ options: ${OBJ}: config.mk -gif2if: gif2if.o +png2ff: png2ff.o @echo CC -o $@ - @${CC} -o $@ gif2if.o ${GIF_LIBS} ${LDFLAGS} + @${CC} -o $@ png2ff.o ${PNG_LIBS} ${LDFLAGS} -jpg2if: jpg2if.o +ff2png: ff2png.o @echo CC -o $@ - @${CC} -o $@ jpg2if.o ${JPEG_LIBS} ${LDFLAGS} - -png2if: png2if.o - @echo CC -o $@ - @${CC} -o $@ png2if.o ${PNG_LIBS} ${LDFLAGS} - -if2png: if2png.o - @echo CC -o $@ - @${CC} -o $@ if2png.o ${PNG_LIBS} ${LDFLAGS} + @${CC} -o $@ ff2png.o ${PNG_LIBS} ${LDFLAGS} clean: @echo cleaning - @rm -f png2if if2png jpg2if gif2if ${OBJ} + @rm -f png2ff ff2png ${OBJ} install: all @echo installing executable files to ${DESTDIR}${PREFIX}/bin @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f png2if jpg2if if2png gif2if ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/png2if - @chmod 755 ${DESTDIR}${PREFIX}/bin/jpg2if - @chmod 755 ${DESTDIR}${PREFIX}/bin/if2png - @chmod 755 ${DESTDIR}${PREFIX}/bin/gif2if + @cp -f png2ff ff2png ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/png2ff + @chmod 755 ${DESTDIR}${PREFIX}/bin/ff2png uninstall: @echo removing executable files from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/png2if - @rm -f ${DESTDIR}${PREFIX}/bin/jpg2if - @rm -f ${DESTDIR}${PREFIX}/bin/if2png - @rm -f ${DESTDIR}${PREFIX}/bin/gif2if + @rm -f ${DESTDIR}${PREFIX}/bin/png2ff + @rm -f ${DESTDIR}${PREFIX}/bin/ff2png .PHONY: all options clean install uninstall diff --git a/SPECIFICATION b/SPECIFICATION @@ -1,18 +1,18 @@ -The imagefile-format is meant to be parsed easily +The farbfeld-format is meant to be parsed easily and used to pipe images losslessly. -# WHY IMAGEFILE? +# WHY FARBFELD? Most current image-formats have their compression incorporated in their format itself. This has some advantages, but reaches its limits with lossless formats (e.g. PNG). -The basic idea of the imagefile-format is to separate +The basic idea of the farbfeld-format is to separate these to and having a completely transparent image-format. Pattern resolution is done while compressing, not while converting the image. -For example, imagefile always stores an alpha-channel, +For example, farbfeld always stores an alpha-channel, even if the image doesn't have alpha-variation. This may sound like a big waste, but as soon as you compress an image of this kind, the bzip2-algorithm @@ -20,24 +20,30 @@ takes care of the easy pattern, that each 4th character has the same value. This leads to almost no overhead while keeping parsing really simple. +Same applies to the idea of having 64 bits per channel. +It sounds excessive, but if you only have 8 bits of +entropy, the compression will take care of it, while +you only need to do the endian-handling for 64 bit +chunks. # FORMAT: Bytes Description -9 imagefile -4 32 bit BE Integer (width) -4 32 bit BE Integer (height) -[1111] RGBA-row-aligned-pixel-array +8 farbfeld +4 32 bit BE Unsigned Integer (width) +4 32 bit BE Unsigned Integer (height) +[2222] RGBA-row-aligned-pixel-array + 16 bit BE Unsigned Integers (per channel) # EXAMPLES: encoding: -png2if < example.png > example.if -png2if < example.png | bzip2 > example.if.bz2 +png2ff < example.png > example.ff +png2ff < example.png | bzip2 > example.ff.bz2 decoding: -if2png < example.if > example.png -bzcat example.if.bz2 | if2png > example.png +ff2png < example.ff > example.png +bzcat example.ff.bz2 | ff2png > example.png # WHY BZ2? @@ -47,4 +53,4 @@ For normal pictures, the bz2-compression yields roughly the same sizes as png does. Always keep in mind that using PNG involves having to rely on libpng to decode the image for you, whereas -imagefile is a completely transparent format. +farbfeld is a completely transparent format. diff --git a/TODO b/TODO @@ -0,0 +1,3 @@ + o handle truecolor PNG's properly (libpng is painful to use) + o write simpler Makefile + o re-add the old imagefile-tools for gif, jpg, ... diff --git a/config.mk b/config.mk @@ -16,7 +16,7 @@ CPPFLAGS = #CFLAGS = -std=c99 -pedantic -Wall -Wextra -O0 -g -ggdb ${CPPFLAGS} #LDFLAGS = ${LIBS} # optimized -CFLAGS = -std=c99 -pedantic -Wall -Wextra -Os ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wextra -D_DEFAULT_SOURCE -Os ${CPPFLAGS} LDFLAGS = -s ${LIBS} # compiler and linker diff --git a/ff2png.c b/ff2png.c @@ -0,0 +1,90 @@ +/* See LICENSE file for copyright and license details. */ +#include <endian.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <png.h> + +#include "arg.h" + +char *argv0; + +#define HEADER_FORMAT "farbfeld########" + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n", argv0); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + png_structp png_struct_p; + png_infop png_info_p; + uint8_t hdr[17], *png_row; + uint16_t tmp16; + png_uint_32 width, height, i; + png_size_t png_row_len, j; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + /* header */ + if (fread(hdr, 1, strlen(HEADER_FORMAT), stdin) != strlen(HEADER_FORMAT)) { + fprintf(stderr, "failed to read from stdin or input too short\n"); + return 1; + } + if (memcmp("farbfeld", hdr, strlen("farbfeld"))) { + fprintf(stderr, "invalid magic in header\n"); + return 1; + } + width = be32toh((hdr[9] << 0) | (hdr[10] << 8) | (hdr[11] << 16) | (hdr[12] << 24)); + height = be32toh((hdr[13] << 0) | (hdr[14] << 8) | (hdr[15] << 16) | (hdr[16] << 24)); + + /* load png */ + png_struct_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_info_p = png_create_info_struct(png_struct_p); + + if (!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p))) { + fprintf(stderr, "failed to initialize libpng\n"); + return 1; + } + png_init_io(png_struct_p, stdout); + png_set_IHDR(png_struct_p, png_info_p, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png_struct_p, png_info_p); + + /* write rows */ + png_row_len = strlen("RGBA") * width * sizeof(uint8_t); + png_row = malloc(png_row_len); + if (!png_row) { + fprintf(stderr, "failed to allocate row-buffer\n"); + return 1; + } + + for (i = 0; i < height; ++i) { + for (j = 0; j < png_row_len; ++j) { + if (fread(&tmp16, 1, sizeof(uint16_t), stdin) != sizeof(uint16_t)) { + fprintf(stderr, "unexpected EOF or row-skew\n"); + return 1; + } + png_row[j] = be16toh(tmp16) / (1 << 8); + } + png_write_row(png_struct_p, png_row); + } + png_write_end(png_struct_p, NULL); + + /* clean up */ + png_free_data(png_struct_p, png_info_p, PNG_FREE_ALL, -1); + png_destroy_write_struct(&png_struct_p, NULL); + free(png_row); + return 0; +} diff --git a/gif2if.c b/gif2if.c @@ -1,177 +0,0 @@ -/* See LICENSE file for copyright and license details. - * code borrowed from util/gif2rgb.c from giflib-5.0 */ -#include <arpa/inet.h> -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <gif_lib.h> -#include "arg.h" - -char *argv0; - -static void -usage(void) -{ - fprintf(stderr, "usage: %s\n", argv0); - exit(EXIT_FAILURE); -} - -static void -die(const char *s) { - fputs(s, stderr); - exit(EXIT_FAILURE); -} - -void * -emalloc(size_t size) { - void *p; - - if(!(p = malloc(size))) - die("can't malloc\n"); - return p; -} - -int -main(int argc, char *argv[]) -{ - GifRecordType recordtype; - GifFileType *giffile; - GifRowType * gifrows; - GifByteType *extension; - GifColorType *colormapentry; - ColorMapObject *colormap; - uint32_t width, height, rwidth, rheight, val_be; - uint32_t i, j, k; - size_t gif_row_len; - uint8_t *if_row; - int extcode, row, col, imagenum = 0; - int interlacedoffset[] = { 0, 4, 2, 1 }; - int interlacedjumps[] = { 8, 8, 4, 2 }; - - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 0) - usage(); - - /* load gif */ -#if GIFLIB_MAJOR >= 5 - if ((giffile = DGifOpenFileHandle(0, NULL)) == NULL) - die("gif error\n"); -#else - if ((giffile = DGifOpenFileHandle(0)) == NULL) - die("gif error\n"); -#endif - - width = (uint32_t)giffile->SWidth; - height = (uint32_t)giffile->SHeight; - gif_row_len = giffile->SWidth * sizeof(GifPixelType); - gifrows = emalloc(giffile->SHeight * sizeof(GifRowType)); - gifrows[0] = emalloc(gif_row_len); - - /* set color to BackGround. */ - for (i = 0; i < width; i++) - gifrows[0][i] = giffile->SBackGroundColor; - for(i = 1; i < height; i++) { - gifrows[i] = emalloc(gif_row_len); - memcpy(gifrows[i], gifrows[0], gif_row_len); - } - - /* scan the content of the GIF file and load the image(s) in: */ - do { - if (DGifGetRecordType(giffile, &recordtype) == GIF_ERROR) - die("gif error\n"); - - switch (recordtype) { - case IMAGE_DESC_RECORD_TYPE: - if (DGifGetImageDesc(giffile) == GIF_ERROR) - die("gif error\n"); - - /* image position relative to Screen. */ - row = giffile->Image.Top; - col = giffile->Image.Left; - rwidth = giffile->Image.Width; - rheight = giffile->Image.Height; - if (giffile->Image.Left + giffile->Image.Width > giffile->SWidth || - giffile->Image.Top + giffile->Image.Height > giffile->SHeight) { - fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n", imagenum); - exit(EXIT_FAILURE); - } - if (giffile->Image.Interlace) { - /* need to perform 4 passes on the images: */ - for (i = 0; i < 4; i++) { - for (j = row + interlacedoffset[i]; j < row + rheight; j += interlacedjumps[i]) { - if (DGifGetLine(giffile, &gifrows[j][col], rwidth) == GIF_ERROR) - die("gif error\n"); - } - } - } else { - for (i = 0; i < rheight; i++) { - if (DGifGetLine(giffile, &gifrows[row++][col], rwidth) == GIF_ERROR) - die("gif error\n"); - } - } - /* this is set to disallow multiple images */ - recordtype = TERMINATE_RECORD_TYPE; - imagenum++; - break; - case EXTENSION_RECORD_TYPE: - /* Skip any extension blocks in file: */ - if (DGifGetExtension(giffile, &extcode, &extension) == GIF_ERROR) - die("gif error\n"); - while (extension != NULL) { - if (DGifGetExtensionNext(giffile, &extension) == GIF_ERROR) - die("gif error\n"); - } - break; - case TERMINATE_RECORD_TYPE: - break; - default: - break; - } - } while (recordtype != TERMINATE_RECORD_TYPE); - - if(giffile->Image.ColorMap) - colormap = giffile->Image.ColorMap; - else - colormap = giffile->SColorMap; - - if(colormap == NULL) - die("Gif Image does not have a colormap\n"); - - /* write header with big endian width and height-values */ - fprintf(stdout, "imagefile"); - val_be = htonl(width); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - val_be = htonl(height); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - - gif_row_len = width * strlen("RGBA"); - if_row = emalloc(gif_row_len); - - /* write data */ - for (i = 0; i < height; i++) { - for(j = 0, k = 0; j < width; j++, k += 4) { - colormapentry = &colormap->Colors[gifrows[i][j]]; - if_row[k] = colormapentry->Red; - if_row[k+1] = colormapentry->Green; - if_row[k+2] = colormapentry->Blue; - if_row[k+3] = 255; /* TODO: mask? */ - } - if (fwrite(if_row, 1, gif_row_len, stdout) != gif_row_len) - die("fwrite() failed\n"); - } - - /* cleanup */ - for(i = 0; i < height; i++) - free(gifrows[i]); - free(gifrows); - free(if_row); - - return EXIT_SUCCESS; -} diff --git a/if2png.c b/if2png.c @@ -1,87 +0,0 @@ -/* 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 <png.h> -#include "arg.h" - -char *argv0; - -#define HEADER_FORMAT "imagefile########" - -static void -usage(void) -{ - fprintf(stderr, "usage: %s\n", argv0); - exit(EXIT_FAILURE); -} - -int -main(int argc, char *argv[]) -{ - png_structp png_struct_p; - png_infop png_info_p; - uint8_t hdr[17], *png_row; - png_uint_32 width, height, i; - png_size_t png_row_len; - - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 0) - usage(); - - /* header */ - if (fread(hdr, 1, strlen(HEADER_FORMAT), stdin) != strlen(HEADER_FORMAT)) { - fprintf(stderr, "failed to read from stdin or input too short\n"); - return EXIT_FAILURE; - } - if (memcmp("imagefile", hdr, 9)) { - fprintf(stderr, "invalid magic in header\n"); - return EXIT_FAILURE; - } - width = ntohl((hdr[9] << 0) | (hdr[10] << 8) | (hdr[11] << 16) | (hdr[12] << 24)); - height = ntohl((hdr[13] << 0) | (hdr[14] << 8) | (hdr[15] << 16) | (hdr[16] << 24)); - - /* load png */ - png_struct_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - png_info_p = png_create_info_struct(png_struct_p); - - if (!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p))) { - fprintf(stderr, "failed to initialize libpng\n"); - return EXIT_FAILURE; - } - png_init_io(png_struct_p, stdout); - png_set_IHDR(png_struct_p, png_info_p, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_write_info(png_struct_p, png_info_p); - - /* write rows */ - png_row_len = strlen("RGBA") * width * sizeof(uint8_t); - png_row = malloc(png_row_len); - if (!png_row) { - fprintf(stderr, "failed to allocate row-buffer\n"); - return EXIT_FAILURE; - } - - for (i = 0; i < height; ++i) { - if (fread(png_row, 1, png_row_len, stdin) != png_row_len) { - fprintf(stderr, "unexpected EOF or row-skew at %lu\n", (unsigned long)i); - return EXIT_FAILURE; - } - png_write_row(png_struct_p, png_row); - } - png_write_end(png_struct_p, NULL); - - /* clean up */ - png_free_data(png_struct_p, png_info_p, PNG_FREE_ALL, -1); - png_destroy_write_struct(&png_struct_p, NULL); - free(png_row); - return EXIT_SUCCESS; -} diff --git a/jpg2if.c b/jpg2if.c @@ -1,121 +0,0 @@ -/* 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 <setjmp.h> -#include <jpeglib.h> -#include "arg.h" - -char *argv0; - -static jmp_buf setjmp_buffer; - -static void -usage(void) -{ - fprintf(stderr, "usage: %s\n", argv0); - exit(EXIT_FAILURE); -} - -METHODDEF(void) -if_jpeg_error(j_common_ptr cinfo) -{ - /* Always display the message. */ - /* We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); - - /* Return control to the setjmp point */ - longjmp(setjmp_buffer, 1); -} - -int -main(int argc, char *argv[]) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - uint32_t width, height, val_be; - uint8_t *if_row = NULL; - size_t jpeg_row_len, if_row_len, i, dx, sx; - int status = EXIT_FAILURE; - JSAMPARRAY buffer; /* output row buffer */ - - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 0) - usage(); - - /* load jpeg */ - cinfo.err = jpeg_std_error(&jerr); - - jerr.error_exit = if_jpeg_error; - /* Establish the setjmp return context for my_error_exit to use. */ - if (setjmp(setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. */ - goto cleanup; - } - - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, stdin); - - jpeg_read_header(&cinfo, TRUE); - width = cinfo.image_width; - height = cinfo.image_height; - - /* change output for imagefile */ - cinfo.output_components = 3; /* # of color components per pixel */ - cinfo.out_color_space = JCS_RGB; /* colorspace of input image */ - - jpeg_start_decompress(&cinfo); - jpeg_row_len = width * cinfo.output_components; - - /* Make a one-row-high sample array that will go away when done with image */ - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, jpeg_row_len, 1); - if_row_len = strlen("RGBA") * width; - if(!(if_row = malloc(if_row_len))) { - fprintf(stderr, "Can't malloc\n"); - return EXIT_FAILURE; - } - - /* write header with big endian width and height-values */ - fprintf(stdout, "imagefile"); - val_be = htonl(width); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - val_be = htonl(height); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - - while (cinfo.output_scanline < cinfo.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. */ - (void)jpeg_read_scanlines(&cinfo, buffer, 1); - - for(i = 0, dx = 0, sx = 0; i < width; i++, sx += 3, dx += 4) { - if_row[dx] = buffer[0][sx]; - if_row[dx+1] = buffer[0][sx+1]; - if_row[dx+2] = buffer[0][sx+2]; - if_row[dx+3] = 255; - } - /* write data */ - if (fwrite(if_row, 1, if_row_len, stdout) != if_row_len) { - fprintf(stderr, "fwrite() failed\n"); - goto cleanup; - } - } - jpeg_finish_decompress(&cinfo); - status = EXIT_SUCCESS; - -cleanup: - free(if_row); - jpeg_destroy_decompress(&cinfo); - - return status; -} diff --git a/png2ff.c b/png2ff.c @@ -0,0 +1,75 @@ +/* See LICENSE file for copyright and license details. */ +#include <endian.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +#include "arg.h" + +char *argv0; + +static void +usage(void) +{ + fprintf(stderr, "usage:%s\n", argv0); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + png_structp png_struct_p; + png_infop png_info_p; + png_bytepp png_row_p; + int depth, color, interlace; + uint32_t width, height, png_row_len, tmp32, r, i; + uint16_t tmp16; + + ARGBEGIN { + default: + usage(); + } ARGEND + + if (argc) + usage(); + + /* load png */ + png_struct_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL); + png_info_p = png_create_info_struct(png_struct_p); + + if (!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p))) { + fprintf(stderr, "failed to initialize libpng\n"); + return 1; + } + png_init_io(png_struct_p, stdin); + png_set_add_alpha(png_struct_p, 255, PNG_FILLER_AFTER); + png_set_gray_to_rgb(png_struct_p); + png_read_png(png_struct_p, png_info_p, PNG_TRANSFORM_STRIP_16 | + PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); + png_get_IHDR(png_struct_p, png_info_p, &width, &height, &depth, + &color, &interlace, NULL, NULL); + png_row_len = png_get_rowbytes(png_struct_p, png_info_p); + png_row_p = png_get_rows(png_struct_p, png_info_p); + + /* write header */ + fprintf(stdout, "farbfeld"); + tmp32 = htobe32(width); + fwrite(&tmp32, sizeof(uint32_t), 1, stdout); + tmp32 = htobe32(height); + fwrite(&tmp32, sizeof(uint32_t), 1, stdout); + + /* write data */ + /* TODO: allow 16 bit PNGs to be converted losslessly */ + for (r = 0; r < height; ++r) { + for (i = 0; i < png_row_len; i++) { + tmp16 = htobe16((uint16_t)png_row_p[r][i]); + fwrite(&tmp16, sizeof(uint16_t), 1, stdout); + } + } + + /* cleanup */ + png_destroy_read_struct(&png_struct_p, &png_info_p, NULL); + return 0; +} diff --git a/png2if.c b/png2if.c @@ -1,77 +0,0 @@ -/* 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 <png.h> -#include "arg.h" - -char *argv0; - -static void -usage(void) -{ - fprintf(stderr, "usage: %s\n", argv0); - exit(EXIT_FAILURE); -} - -int -main(int argc, char *argv[]) -{ - png_structp png_struct_p; - png_infop png_info_p; - png_bytepp png_row_p; - png_uint_32 width, height, i; - png_size_t png_row_len; - uint32_t val_be; - int depth, color, interlace; - - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 0) - usage(); - - /* load png */ - png_struct_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - png_info_p = png_create_info_struct(png_struct_p); - - if (!png_struct_p || !png_info_p || setjmp(png_jmpbuf(png_struct_p))) { - fprintf(stderr, "failed to initialize libpng"); - return EXIT_FAILURE; - } - png_init_io(png_struct_p, stdin); - png_set_add_alpha(png_struct_p, 255, PNG_FILLER_AFTER); - png_set_gray_to_rgb(png_struct_p); - png_read_png(png_struct_p, png_info_p, PNG_TRANSFORM_STRIP_16 | - PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND , NULL); - png_get_IHDR(png_struct_p, png_info_p, &width, &height, &depth, - &color, &interlace, NULL, NULL); - png_row_len = png_get_rowbytes(png_struct_p, png_info_p); - png_row_p = png_get_rows(png_struct_p, png_info_p); - - /* write header with big endian width and height-values */ - fprintf(stdout, "imagefile"); - val_be = htonl(width); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - val_be = htonl(height); - fwrite(&val_be, sizeof(uint32_t), 1, stdout); - - /* write data */ - for (i = 0; i < height; i++) { - if (fwrite(png_row_p[i], 1, png_row_len, stdout) != png_row_len) { - fprintf(stderr, "fwrite() failed\n"); - return EXIT_FAILURE; - } - } - - /* clean up */ - png_free_data(png_struct_p, png_info_p, PNG_FREE_ALL, -1); - png_destroy_read_struct(&png_struct_p, &png_info_p, NULL); - return EXIT_SUCCESS; -}