farbfeld

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

ff2jpg.c (2477B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <arpa/inet.h>
      3 
      4 #include <errno.h>
      5 #include <inttypes.h>
      6 #include <stdint.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 
     11 #include <jpeglib.h>
     12 
     13 #include "arg.h"
     14 #include "util.h"
     15 
     16 static void
     17 jpeg_error(j_common_ptr js)
     18 {
     19 	fprintf(stderr, "%s: libjpeg: ", argv0);
     20 	(*js->err->output_message)(js);
     21 	exit(1);
     22 }
     23 
     24 static void
     25 jpeg_setup_writer(struct jpeg_compress_struct *s, struct jpeg_error_mgr *e,
     26                   uint32_t w, uint32_t h, int quality, int opt)
     27 {
     28 	jpeg_create_compress(s);
     29 	e->error_exit = jpeg_error;
     30 	s->err = jpeg_std_error(e);
     31 
     32 	jpeg_stdio_dest(s, stdout);
     33 	s->image_width = w;
     34 	s->image_height = h;
     35 	s->input_components = 3;     /* color components per pixel */
     36 	s->in_color_space = JCS_RGB; /* output color space */
     37 	jpeg_set_defaults(s);
     38 
     39 	if (opt) {
     40 		s->optimize_coding = 1;
     41 	}
     42 	jpeg_set_quality(s, quality, 1);
     43 
     44 	jpeg_start_compress(s, 1);
     45 }
     46 
     47 static void
     48 usage(void)
     49 {
     50 	die("usage: %s [-b colour] [-o] [-q quality]", argv0);
     51 }
     52 
     53 int
     54 main(int argc, char *argv[])
     55 {
     56 	struct jpeg_compress_struct jcomp;
     57 	struct jpeg_error_mgr jerr;
     58 	size_t rowlen;
     59 	uint64_t a;
     60 	uint32_t width, height, i, j, k, l;
     61 	uint16_t *row, mask[3] = { 0xffff, 0xffff, 0xffff };
     62 	uint8_t *rowout;
     63 	int optimize = 0, quality = 85;
     64 
     65 	/* arguments */
     66 	ARGBEGIN {
     67 	case 'b':
     68 		if (parse_mask(EARGF(usage()), mask)) {
     69 			usage();
     70 		}
     71 		break;
     72 	case 'o':
     73 		optimize = 1;
     74 		break;
     75 	case 'q':
     76 		quality = estrtonum(EARGF(usage()), 0, 100);
     77 		break;
     78 	default:
     79 		usage();
     80 	} ARGEND
     81 
     82 	if (argc) {
     83 		usage();
     84 	}
     85 
     86 	/* prepare */
     87 	ff_read_header(&width, &height);
     88 	jpeg_setup_writer(&jcomp, &jerr, width, height, quality, optimize);
     89 	row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(uint16_t));
     90 	rowlen = width * (sizeof("RGBA") - 1);
     91 	rowout = ereallocarray(NULL, width, (sizeof("RGB") - 1) * sizeof(uint8_t));
     92 
     93 	/* write data */
     94 	for (i = 0; i < height; ++i) {
     95 		efread(row, sizeof(uint16_t), rowlen, stdin);
     96 		for (j = 0, k = 0; j < rowlen; j += 4, k += 3) {
     97 			a = ntohs(row[j + 3]);
     98 			for (l = 0; l < 3; l++) {
     99 				/* alpha blending and 8-bit-reduction */
    100 				rowout[k + l] = (a * ntohs(row[j + l]) +
    101 				                 (UINT16_MAX - a) * mask[l]) /
    102 				                (UINT16_MAX *
    103 						 (UINT16_MAX / UINT8_MAX));
    104 			}
    105 		}
    106 		jpeg_write_scanlines(&jcomp, &rowout, 1);
    107 	}
    108 
    109 	/* clean up */
    110 	jpeg_finish_compress(&jcomp);
    111 	jpeg_destroy_compress(&jcomp);
    112 
    113 	return fshut(stdout, "<stdout>");
    114 }