farbfeld

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

commit de61085a0413f2f7570a89df345eb875d1a0298c
parent 7b03f52a130a12355d87bc05f028db31963112cc
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:
ff2png.c | 32++++++++++++++++----------------
jpg2ff.c | 80++++++++++++++++++++++++++++++++++++++++---------------------------------------
png2ff.c | 30++++++++++++------------------
3 files changed, 69 insertions(+), 73 deletions(-)

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