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