commit b880be4
sewn
·
2026-05-07 23:12:58 +0000 UTC
parent 470591f
implement color, fit, fill, tile, stretch
1 files changed,
+119,
-19
M
wawa.c
M
wawa.c
+119,
-19
1@@ -1,4 +1,5 @@
2 /* See LICENSE file for copyright and license details. */
3+#include <byteswap.h>
4 #include <fcntl.h>
5 #include <stdbool.h>
6 #include <sys/mman.h>
7@@ -31,23 +32,27 @@ struct output {
8 struct wl_list link;
9 };
10
11+static struct wl_display *display;
12+static struct wl_registry *registry;
13+static struct wl_compositor *compositor;
14+static struct wl_shm *shm;
15+static struct zwlr_layer_shell_v1 *layer_shell;
16+static struct wl_list outputs;
17+
18 /*
19 * Must be valid when a single monitor is misconfigured
20 * or during startup, after which the image is freed.
21 */
22 struct {
23+ FILE *fp;
24 int width, height;
25 unsigned char *data;
26 } image;
27
28-static struct wl_display *display;
29-static struct wl_registry *registry;
30-static struct wl_compositor *compositor;
31-static struct wl_shm *shm;
32-static struct zwlr_layer_shell_v1 *layer_shell;
33-static struct wl_list outputs;
34+static uint32_t color;
35
36-static const char *filename;
37+static void image_fill(unsigned char *dst, struct output *output);
38+static void (*image_modify)(unsigned char *, struct output *) = image_fill;
39
40 static void
41 die(const char *fmt, ...)
42@@ -69,7 +74,61 @@ die(const char *fmt, ...)
43 }
44
45 static void
46-image_crop(unsigned char *dst, struct output *output)
47+parse_color(const char *src)
48+{
49+ int len;
50+
51+ if (src[0] == '#')
52+ src++;
53+ len = strlen(src);
54+ if (len != 6 && len != 8)
55+ die("bad color: %s", src);
56+
57+ color = strtoul(src, NULL, 16);
58+ if (len == 6)
59+ color = (color << 8) | 0xFF;
60+
61+ color = bswap_32(color);
62+}
63+
64+static void
65+image_color(unsigned char *dst, struct output *output)
66+{
67+ for (size_t i = 0; i < output->size; i += 4)
68+ memcpy(dst + i, &color, 4);
69+}
70+
71+static void
72+image_stretch(unsigned char *dst, struct output *output)
73+{
74+ stbir_resize_uint8_linear(
75+ image.data, image.width, image.height, image.width * 4,
76+ dst, output->width, output->height, output->stride, 4);
77+}
78+
79+static void
80+image_fit(unsigned char *dst, struct output *output)
81+{
82+ struct {
83+ int width, height;
84+ int x, y;
85+ } crop;
86+ double factor;
87+
88+ factor = fmin((double)output->width/image.width, (double)output->height/image.height);
89+ crop.width = image.width * factor;
90+ crop.height = image.height * factor;
91+ crop.x = (output->width - crop.width) / 2;
92+ crop.y = (output->height - crop.height) / 2;
93+ stbir_resize_uint8_linear(
94+ image.data, image.width, image.height, image.width * 4,
95+ dst + (crop.y * output->stride) + (crop.x * 4),
96+ crop.width, crop.height, output->stride,
97+ 4);
98+}
99+
100+static void
101+image_fill(unsigned char *dst, struct output *output)
102 {
103 struct {
104 int width, height;
105@@ -78,16 +137,38 @@ image_crop(unsigned char *dst, struct output *output)
106 double factor;
107
108 factor = fmin((double)image.width/output->width, (double)image.height/output->height);
109- crop.x = (image.width - (output->width * factor)) / 2;
110- crop.y = (image.height - (output->height * factor)) / 2;
111 crop.width = output->width * factor;
112 crop.height = output->height * factor;
113+ crop.x = (image.width - (crop.width)) / 2;
114+ crop.y = (image.height - (crop.height)) / 2;
115 stbir_resize_uint8_linear(
116- image.data + (crop.y * image.width + crop.x) * 4, crop.width, crop.height, image.width * 4,
117+ image.data + (crop.y * image.width + crop.x) * 4,
118+ crop.width, crop.height, image.width * 4,
119 dst, output->width, output->height, output->stride,
120 4);
121 }
122
123+static void
124+image_tile(unsigned char *dst, struct output *o)
125+{
126+ unsigned char *to, *src;
127+ uint16_t off_x, off_y, w, h;
128+
129+ /* implementation shamelessly stolen from xwallpaper, MIT:
130+ * 2025 Tobias Stoeckmann <tobias@stoeckmann.org> */
131+ for (off_y = 0; off_y < o->height; off_y += image.height) {
132+ h = (off_y + image.height > o->height) ? o->height - off_y : image.height;
133+ for (off_x = 0; off_x < o->width; off_x += image.width) {
134+ w = (off_x + image.width > o->width) ? o->width - off_x : image.width;
135+ for (int y = 0; y < h; y++) {
136+ to = dst + ((off_y + y) * o->stride);
137+ src = image.data + (y * image.width * 4);
138+ memcpy(to + (off_x * 4), src, w * 4);
139+ }
140+ }
141+ }
142+}
143+
144 static struct wl_buffer *
145 output_load_image(struct output *output)
146 {
147@@ -113,7 +194,7 @@ output_load_image(struct output *output)
148 wl_shm_pool_destroy(shm_pool);
149 close(fd);
150
151- image_crop(data, output);
152+ image_modify(data, output);
153
154 /* RGBA->BGRA */
155 for (int i = 0; i < output->size; i += 4) {
156@@ -138,9 +219,9 @@ layer_surface_handle_configure(void *data, struct zwlr_layer_surface_v1 *layer_s
157 output->configured = width == output->width && height == output->height;
158 if (output->configured) return;
159
160- if (!image.data) {
161+ if (!image.data && image.fp) {
162 fputs("loaded image", stderr);
163- if (!(image.data = stbi_load(filename,
164+ if (!(image.data = stbi_load_from_file(image.fp,
165 &image.width, &image.height, NULL, 4)))
166 die("failed to load image: %s", stbi_failure_reason());
167 }
168@@ -247,16 +328,29 @@ static const struct wl_registry_listener registry_listener = {
169 .global_remove = registry_handle_remove,
170 };
171
172+
173+
174 int
175 main(int argc, char *argv[])
176 {
177- if (argc != 2) {
178- fprintf(stderr, "usage: %s filename\n", argv[0]);
179- return EXIT_FAILURE;
180+ switch (argc) {
181+ case 2:
182+ parse_color(argv[1]);
183+ image_modify = image_color;
184+ break;
185+ case 3:
186+ if (!strcmp(argv[1], "stretch")) image_modify = image_stretch;
187+ else if (!strcmp(argv[1], "fit")) image_modify = image_fit;
188+ else if (!strcmp(argv[1], "fill")) image_modify = image_fill;
189+ else if (!strcmp(argv[1], "tile")) image_modify = image_tile;
190+ else goto usage;
191+
192+ if (!(image.fp = fopen(argv[2], "rb"))) die("fopen %s:", argv[2]);
193+ break;
194+ default:
195+ goto usage;
196 }
197
198- filename = argv[1];
199-
200 if (!(display = wl_display_connect(NULL)))
201 die("failed to connect to wayland");
202
203@@ -273,4 +367,10 @@ main(int argc, char *argv[])
204 ;
205
206 return EXIT_SUCCESS;
207+
208+usage:
209+ fprintf(stderr, "usage: %s stretch|fit|fill|tile filename\n"
210+ " %s RRGGBBAA\n",
211+ argv[0], argv[0]);
212+ return EXIT_FAILURE;
213 }