Refactor tools and increase performance by ~70% - 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 de61085a0413f2f7570a89df345eb875d1a0298c
 (DIR) parent 7b03f52a130a12355d87bc05f028db31963112cc
 (HTM) Author: FRIGN <dev@frign.de>
       Date:   Mon,  1 Feb 2016 13:36:55 +0100
       
       Refactor tools and increase performance by ~70%
       
       Instead of calling fwrite on each channel, we write one big chunk
       of a line.
       This increases performance by around 70% compared to version 1 and
       the farbfeld tools are now roughly fast as imagemagick's convert.
       
       I also refactored the code, removed unnecessary variables and unified
       the variable naming and error reporting a bit.
       Inside jpg2ff, the loop didn't need 3 variables.
       
       Diffstat:
         M ff2png.c                            |      32 ++++++++++++++++----------------
         M jpg2ff.c                            |      80 ++++++++++++++++---------------
         M png2ff.c                            |      30 ++++++++++++------------------
       
       3 files changed, 69 insertions(+), 73 deletions(-)
       ---
 (DIR) diff --git a/ff2png.c b/ff2png.c
       @@ -9,7 +9,7 @@
        
        #include <png.h>
        
       -#define HEADER "farbfeld########"
       +#define HDR "farbfeld########"
        
        static char *argv0;
        
       @@ -25,9 +25,9 @@ main(int argc, char *argv[])
        {
                png_structp pngs;
                png_infop pngi;
       -        size_t png_row_len, j;
       +        size_t rowlen;
                uint32_t width, height, i;
       -        uint16_t tmp16, *png_row;
       +        uint16_t *row;
                uint8_t hdr[16];
        
                argv0 = argv[0], argc--, argv++;
       @@ -38,11 +38,10 @@ main(int argc, char *argv[])
                }
        
                /* header */
       -        if (fread(hdr, 1, strlen(HEADER), stdin) != strlen(HEADER)) {
       -                fprintf(stderr, "%s: incomplete header\n", argv0);
       -                return 1;
       +        if (fread(hdr, 1, sizeof(HDR) - 1, stdin) != sizeof(HDR) - 1) {
       +                goto readerr;
                }
       -        if (memcmp("farbfeld", hdr, strlen("farbfeld"))) {
       +        if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) {
                        fprintf(stderr, "%s: invalid magic value\n", argv0);
                        return 1;
                }
       @@ -65,23 +64,24 @@ main(int argc, char *argv[])
                png_write_info(pngs, pngi);
        
                /* write rows */
       -        png_row_len = strlen("RGBA") * width * sizeof(uint16_t);
       -        if (!(png_row = malloc(png_row_len))) {
       +        rowlen = (sizeof("RGBA") - 1) * width;
       +        if (!(row = malloc(rowlen * sizeof(uint16_t)))) {
                        fprintf(stderr, "%s: malloc: out of memory\n", argv0);
                        return 1;
                }
                for (i = 0; i < height; ++i) {
       -                for (j = 0; j < png_row_len / sizeof(uint16_t); ++j) {
       -                        if (fread(&tmp16, sizeof(uint16_t), 1, stdin) != 1) {
       -                                fprintf(stderr, "%s: unexpected EOF\n", argv0);
       -                                return 1;
       -                        }
       -                        png_row[j] = tmp16;
       +                if (fread(row, sizeof(uint16_t), rowlen, stdin) != rowlen) {
       +                        goto readerr;
                        }
       -                png_write_row(pngs, (uint8_t *)png_row);
       +                png_write_row(pngs, (uint8_t *)row);
                }
                png_write_end(pngs, NULL);
                png_destroy_write_struct(&pngs, NULL);
        
                return 0;
       +readerr:
       +        fprintf(stderr, "%s: fread: ", argv0);
       +        perror(NULL);
       +
       +        return 1;
        }
 (DIR) diff --git a/jpg2ff.c b/jpg2ff.c
       @@ -12,22 +12,22 @@
        static char *argv0;
        
        METHODDEF(void)
       -jpeg_error(j_common_ptr cinfo)
       +jpeg_error(j_common_ptr js)
        {
                fprintf(stderr, "%s: libjpeg: ", argv0);
       -        (*cinfo->err->output_message)(cinfo);
       +        (*js->err->output_message)(js);
                exit(1);
        }
        
        int
        main(int argc, char *argv[])
        {
       -        struct jpeg_decompress_struct cinfo;
       +        struct jpeg_decompress_struct js;
                struct jpeg_error_mgr jerr;
       -        uint32_t width, height, val_be;
       -        uint16_t *ff_row;
       -        size_t jpeg_row_len, ff_row_len, i, dx, sx;
       -        JSAMPARRAY buffer; /* output row buffer */
       +        uint32_t width, height, tmp32;
       +        uint16_t *row;
       +        size_t rowlen, i;
       +        JSAMPARRAY jpgrow;
        
                argv0 = argv[0], argc--, argv++;
        
       @@ -37,61 +37,63 @@ main(int argc, char *argv[])
                }
        
                /* load jpg */
       -        cinfo.err = jpeg_std_error(&jerr);
       +        js.err = jpeg_std_error(&jerr);
                jerr.error_exit = jpeg_error;
        
       -        jpeg_create_decompress(&cinfo);
       +        jpeg_create_decompress(&js);
        
       -        jpeg_stdio_src(&cinfo, stdin);
       +        jpeg_stdio_src(&js, stdin);
        
       -        jpeg_read_header(&cinfo, TRUE);
       -        width = cinfo.image_width;
       -        height = cinfo.image_height;
       +        jpeg_read_header(&js, 1);
       +        width = js.image_width;
       +        height = js.image_height;
        
                /* set output format */
       -        cinfo.output_components = 3;     /* color components per pixel */
       -        cinfo.out_color_space = JCS_RGB; /* input color space */
       +        js.output_components = 3;     /* color components per pixel */
       +        js.out_color_space = JCS_RGB; /* input color space */
        
       -        jpeg_start_decompress(&cinfo);
       -        jpeg_row_len = width * cinfo.output_components;
       +        jpeg_start_decompress(&js);
        
                /* create output buffers */
       -        buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,
       -                                            JPOOL_IMAGE, jpeg_row_len, 1);
       -        ff_row_len = strlen("RGBA") * width;
       -        if(!(ff_row = malloc(ff_row_len * sizeof(uint16_t)))) {
       +        jpgrow = (*js.mem->alloc_sarray)((j_common_ptr)&js,
       +                                         JPOOL_IMAGE, width *
       +                                         js.output_components, 1);
       +        rowlen = strlen("RGBA") * width;
       +        if(!(row = malloc(rowlen * sizeof(uint16_t)))) {
                        fprintf(stderr, "%s: malloc: out of memory\n", argv0);
                        return 1;
                }
        
                /* write header */
                fprintf(stdout, "farbfeld");
       -        val_be = htonl(width);
       -        if (fwrite(&val_be, sizeof(uint32_t), 1, stdout) != 1)
       +        tmp32 = htonl(width);
       +        if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1)
                        goto writerr;
       -        val_be = htonl(height);
       -        if (fwrite(&val_be, sizeof(uint32_t), 1, stdout) != 1)
       +        tmp32 = htonl(height);
       +        if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1)
                        goto writerr;
        
       -        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. */
       -                jpeg_read_scanlines(&cinfo, buffer, 1);
       -
       -                for (i = 0, dx = 0, sx = 0; i < width; i++, sx += 3, dx += 4) {
       -                        ff_row[dx]   = htons(buffer[0][sx]   * 257);
       -                        ff_row[dx+1] = htons(buffer[0][sx+1] * 257);
       -                        ff_row[dx+2] = htons(buffer[0][sx+2] * 257);
       -                        ff_row[dx+3] = htons(65535);
       +        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);
       +
       +                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);
                        }
        
                        /* write data */
       -                if (fwrite(ff_row, 2, ff_row_len, stdout) != ff_row_len)
       +                if (fwrite(row, 2, rowlen, stdout) != rowlen)
                                goto writerr;
                }
       -        jpeg_finish_decompress(&cinfo);
       -        jpeg_destroy_decompress(&cinfo);
       +        jpeg_finish_decompress(&js);
       +        jpeg_destroy_decompress(&js);
        
                return 0;
        writerr:
 (DIR) diff --git a/png2ff.c b/png2ff.c
       @@ -23,9 +23,9 @@ main(int argc, char *argv[])
        {
                png_structp pngs;
                png_infop pngi;
       -        uint32_t width, height, outrowlen, tmp32, r, i;
       -        uint16_t *outrow;
       -        uint8_t **png_row_p;
       +        uint32_t width, height, rowlen, tmp32, r, i;
       +        uint16_t *row;
       +        uint8_t **pngrows;
        
                argv0 = argv[0], argc--, argv++;
        
       @@ -54,15 +54,13 @@ main(int argc, char *argv[])
                             PNG_TRANSFORM_EXPAND, NULL);
                width = png_get_image_width(pngs, pngi);
                height = png_get_image_height(pngs, pngi);
       -        png_row_p = png_get_rows(pngs, pngi);
       -
       +        pngrows = png_get_rows(pngs, pngi);
                /* allocate output row buffer */
       -        outrowlen = width * strlen("RGBA");
       -        if (!(outrow = malloc(outrowlen * sizeof(uint16_t)))) {
       +        rowlen = width * strlen("RGBA");
       +        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);
       @@ -71,27 +69,23 @@ main(int argc, char *argv[])
                tmp32 = htonl(height);
                if (fwrite(&tmp32, sizeof(uint32_t), 1, stdout) != 1)
                        goto writerr;
       -
                /* write data */
                switch(png_get_bit_depth(pngs, pngi)) {
                case 8:
                        for (r = 0; r < height; ++r) {
       -                        for (i = 0; i < outrowlen; i++) {
       -                                outrow[i] = htons(257 * png_row_p[r][i]);
       +                        for (i = 0; i < rowlen; i++) {
       +                                row[i] = htons(257 * pngrows[r][i]);
                                }
       -                        if (fwrite(outrow, sizeof(uint16_t), outrowlen,
       -                                   stdout) != outrowlen) {
       +                        if (fwrite(row, sizeof(uint16_t), rowlen,
       +                                   stdout) != rowlen) {
                                        goto writerr;
                                }
                        }
                        break;
                case 16:
                        for (r = 0; r < height; ++r) {
       -                        for (i = 0; i < outrowlen; ++i) {
       -                                outrow[i] = ((uint16_t *)png_row_p[r])[i];
       -                        }
       -                        if (fwrite(outrow, sizeof(uint16_t), outrowlen,
       -                                   stdout) != outrowlen) {
       +                        if (fwrite(pngrows[r], sizeof(uint16_t),
       +                                   rowlen, stdout) != rowlen) {
                                        goto writerr;
                                }
                        }