This makes it possible to render output buffers in a different color space, by specifying an ICC profile for the output.master
							parent
							
								
									2e9139df66
								
							
						
					
					
						commit
						40ca4150b2
					
				| @ -0,0 +1,101 @@ | ||||
| #include <fcntl.h> | ||||
| #include <strings.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <wlr/render/color.h> | ||||
| #include "sway/commands.h" | ||||
| #include "sway/config.h" | ||||
| 
 | ||||
| static bool read_file_into_buf(const char *path, void **buf, size_t *size) { | ||||
| 	/* Why not use fopen/fread directly? glibc will succesfully open directories,
 | ||||
| 	 * not just files, and supports seeking on them. Instead, we directly | ||||
| 	 * work with file descriptors and use the more consistent open/fstat/read. */ | ||||
| 	int fd = open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC); | ||||
| 	if (fd == -1) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	char *b = NULL; | ||||
| 	struct stat info; | ||||
| 	if (fstat(fd, &info) == -1) { | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	// only regular files, to avoid issues with e.g. opening pipes
 | ||||
| 	if (!S_ISREG(info.st_mode)) { | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	off_t s = info.st_size; | ||||
| 	if (s <= 0) { | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	b = calloc(1, s); | ||||
| 	if (!b) { | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	size_t nread = 0; | ||||
| 	while (nread < (size_t)s) { | ||||
| 		size_t to_read = (size_t)s - nread; | ||||
| 		ssize_t r = read(fd, b + nread, to_read); | ||||
| 		if ((r == -1 && errno != EINTR) || r == 0) { | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		nread += (size_t)r; | ||||
| 	} | ||||
| 	close(fd); | ||||
| 	*buf = b; | ||||
| 	*size = (size_t)s; | ||||
| 	return true; // success
 | ||||
| fail: | ||||
| 	free(b); | ||||
| 	close(fd); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| struct cmd_results *output_cmd_color_profile(int argc, char **argv) { | ||||
| 	if (!config->handler_context.output_config) { | ||||
| 		return cmd_results_new(CMD_FAILURE, "Missing output config"); | ||||
| 	} | ||||
| 	if (!argc) { | ||||
| 		return cmd_results_new(CMD_INVALID, "Missing color_profile first argument."); | ||||
| 	} | ||||
| 
 | ||||
| 	if (strcmp(*argv, "srgb") == 0) { | ||||
| 		wlr_color_transform_unref(config->handler_context.output_config->color_transform); | ||||
| 		config->handler_context.output_config->color_transform = NULL; | ||||
| 		config->handler_context.output_config->set_color_transform = true; | ||||
| 
 | ||||
| 		config->handler_context.leftovers.argc = argc - 1; | ||||
| 		config->handler_context.leftovers.argv = argv + 1; | ||||
| 	} else if (strcmp(*argv, "icc") == 0) { | ||||
| 		if (argc < 2) { | ||||
| 			return cmd_results_new(CMD_INVALID, | ||||
| 				"Invalid color profile specification: icc type requires a file"); | ||||
| 		} | ||||
| 		void *data = NULL; | ||||
| 		size_t size = 0; | ||||
| 		if (!read_file_into_buf(argv[1], &data, &size)) { | ||||
| 			return cmd_results_new(CMD_FAILURE, | ||||
| 				"Failed to load color profile: could not read ICC file"); | ||||
| 		} | ||||
| 
 | ||||
| 		struct wlr_color_transform *tmp = | ||||
| 			wlr_color_transform_init_linear_to_icc(data, size); | ||||
| 		if (!tmp) { | ||||
| 			free(data); | ||||
| 			return cmd_results_new(CMD_FAILURE, | ||||
| 				"Failed to load color profile: failed to initialize transform from ICC"); | ||||
| 		} | ||||
| 		free(data); | ||||
| 
 | ||||
| 		wlr_color_transform_unref(config->handler_context.output_config->color_transform); | ||||
| 		config->handler_context.output_config->color_transform = tmp; | ||||
| 		config->handler_context.output_config->set_color_transform = true; | ||||
| 
 | ||||
| 		config->handler_context.leftovers.argc = argc - 2; | ||||
| 		config->handler_context.leftovers.argv = argv + 2; | ||||
| 	} else { | ||||
| 		return cmd_results_new(CMD_INVALID, | ||||
| 			"Invalid color profile specification: first argument should be icc|srgb"); | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue