notashelf /
46ea9402424d58c5b637008292a5c379e05f9c7b
chroma
publicLightweight wallpaper daemon for Wayland
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.gitCommit 46ea9402424d
tarballunverified1 files changed+147-7
@@ -24,8 +24,76 @@ static long get_file_size(const char *path) { return st.st_size; } -// Load image from file-int chroma_image_load(chroma_image_t *image, const char *path) {+// Calculate optimal image size based on output dimensions+static void calculate_optimal_size(int original_width, int original_height,+ int max_output_width, int max_output_height,+ int *optimal_width, int *optimal_height) {+ // If image is smaller than outputs, keep original size+ if (original_width <= max_output_width &&+ original_height <= max_output_height) {+ *optimal_width = original_width;+ *optimal_height = original_height;+ return;+ }++ // Calculate scale factor to fit within max output dimensions+ float scale_x = (float)max_output_width / original_width;+ float scale_y = (float)max_output_height / original_height;+ float scale = (scale_x < scale_y) ? scale_x : scale_y;++ // Apply scale factor with minimum size to avoid too small images+ scale = (scale > 1.0f) ? 1.0f : scale;+ scale = (scale < 0.25f) ? 0.25f : scale; // XXX: don't scale below 25%++ *optimal_width = (int)(original_width * scale);+ *optimal_height = (int)(original_height * scale);++ // Ensure even dimensions for better GPU alignment+ *optimal_width = (*optimal_width / 2) * 2;+ *optimal_height = (*optimal_height / 2) * 2;+}++// FIXME: this is a very simple way of implementing box filter downsampling for+// memory efficiency Could be better, but this is good enough *for the time+// being*. Must be revisited in the future to see how it stands as the program+// evolves.+static int downsample_image(unsigned char *src_data, int src_width,+ int src_height, unsigned char *dst_data,+ int dst_width, int dst_height) {+ if (!src_data || !dst_data) {+ return -1;+ }++ float x_ratio = (float)src_width / dst_width;+ float y_ratio = (float)src_height / dst_height;++ for (int y = 0; y < dst_height; y++) {+ for (int x = 0; x < dst_width; x++) {+ // Calculate corresponding source pixel+ int src_x = (int)(x * x_ratio);+ int src_y = (int)(y * y_ratio);++ // Ensure we're within bounds+ src_x = (src_x >= src_width) ? src_width - 1 : src_x;+ src_y = (src_y >= src_height) ? src_height - 1 : src_y;++ // Copy pixel (RGBA)+ int src_idx = (src_y * src_width + src_x) * 4;+ int dst_idx = (y * dst_width + x) * 4;++ dst_data[dst_idx + 0] = src_data[src_idx + 0]; // R+ dst_data[dst_idx + 1] = src_data[src_idx + 1]; // G+ dst_data[dst_idx + 2] = src_data[src_idx + 2]; // B+ dst_data[dst_idx + 3] = src_data[src_idx + 3]; // A+ }+ }++ return 0;+}++// Load image from file with configurable downsampling+int chroma_image_load(chroma_image_t *image, const char *path,+ const chroma_config_t *config) { if (!image || !path) { chroma_log("ERROR", "Invalid parameters for image loading"); return CHROMA_ERROR_INIT;@@ -77,15 +145,87 @@ int chroma_image_load(chroma_image_t *image, const char *path) { return CHROMA_ERROR_IMAGE; } + // Store original dimensions before potential downsampling+ int original_width = image->width;+ int original_height = image->height;++ // Apply intelligent downsampling if enabled+ bool should_downsample = false;+ int optimal_width = original_width;+ int optimal_height = original_height;++ if (config && config->enable_downsampling) {+ calculate_optimal_size(original_width, original_height,+ config->max_output_width, config->max_output_height,+ &optimal_width, &optimal_height);++ // Apply minimum scale factor constraint+ float scale_x = (float)optimal_width / original_width;+ float scale_y = (float)optimal_height / original_height;+ float scale = (scale_x < scale_y) ? scale_x : scale_y;++ if (scale < config->min_scale_factor) {+ scale = config->min_scale_factor;+ optimal_width = (int)(original_width * scale);+ optimal_height = (int)(original_height * scale);++ // Ensure even dimensions+ optimal_width = (optimal_width / 2) * 2;+ optimal_height = (optimal_height / 2) * 2;+ }++ should_downsample =+ (optimal_width < original_width || optimal_height < original_height);+ }++ // Downsamp if needed and enabled+ if (should_downsample) {+ chroma_log("INFO",+ "Downsampling image from %dx%d to %dx%d (%.1f%% of original)",+ original_width, original_height, optimal_width, optimal_height,+ (float)(optimal_width * optimal_height) /+ (original_width * original_height) * 100.0f);++ size_t optimal_size = (size_t)optimal_width * optimal_height * 4;+ unsigned char *downsampled_data = malloc(optimal_size);+ if (!downsampled_data) {+ chroma_log("ERROR", "Failed to allocate memory for downsampled image");+ chroma_image_free(image);+ return CHROMA_ERROR_MEMORY;+ }++ if (downsample_image(image->data, original_width, original_height,+ downsampled_data, optimal_width,+ optimal_height) != 0) {+ chroma_log("ERROR", "Failed to downsample image");+ free(downsampled_data);+ chroma_image_free(image);+ return CHROMA_ERROR_IMAGE;+ }++ stbi_image_free(image->data);+ image->data = downsampled_data;+ image->width = optimal_width;+ image->height = optimal_height;++ chroma_log("DEBUG", "Successfully downsampled image to %dx%d",+ optimal_width, optimal_height);+ } else if (config && !config->enable_downsampling) {+ chroma_log("DEBUG",+ "Downsampling disabled, keeping original resolution %dx%d",+ original_width, original_height);+ }+ image->loaded = true; // Calculate and log memory allocation size_t image_size = (size_t)image->width * image->height * image->channels; chroma_log_resource_allocation("image_data", image_size, path); - chroma_log("INFO", "Loaded image: %s (%dx%d, %d channels, %.2f MB)", path,+ chroma_log("INFO", "Loaded image: %s (%dx%d, %d channels, %.2f MB)%s", path, image->width, image->height, image->channels,- (double)image_size / (1024.0 * 1024.0));+ (double)image_size / (1024.0 * 1024.0),+ should_downsample ? " (downsampled)" : ""); return CHROMA_OK; }@@ -159,8 +299,8 @@ chroma_image_t *chroma_image_get_or_load(chroma_state_t *state, state->image_count++; } - // Load the image- if (chroma_image_load(image, path) != CHROMA_OK) {+ // Load the image with configuration+ if (chroma_image_load(image, path, &state->config) != CHROMA_OK) { // If this was a new slot, decrement count if (!existing) { state->image_count--;@@ -241,7 +381,7 @@ void chroma_image_init_stb(void) { // Set stb_image options stbi_set_flip_vertically_on_load(0); - // These could be made configurable+ // FIXME: these could be made configurable stbi_ldr_to_hdr_gamma(2.2f); stbi_ldr_to_hdr_scale(1.0f);