| ff2jpg.c - 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 … | |
| 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, optimiz… | |
| 89 row = ereallocarray(NULL, width, (sizeof("RGBA") - 1) * sizeof(u… | |
| 90 rowlen = width * (sizeof("RGBA") - 1); | |
| 91 rowout = ereallocarray(NULL, width, (sizeof("RGB") - 1) * sizeof… | |
| 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… | |
| 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 } |