@sdetweil said in Contrasting text on changing background:
@mwm341 I want that too. text over photos. haven’t figured out a way yet.
I kludged something together today with the MMM-Wallpaper module. It’s not elegant, but it’s been working for me so far.
What I’m doing is having the module draw the image onto an off-screen canvas and compute its average brightness using the luminance formula. Based on whether this brightness exceeds a defined threshold (115 has been working for me), the module then updates a global CSS variable with either a light or dark text color.
I’m using color: var(--dynamic-text-color);
as the variable. Since it’s determining global brightness, it can still “miss” picking a good color for each module.
Depending on compute load, I’m thinking an update would be to determine that brightness value for each quadrant of an image then creating a variable for each quadrant and setting the text style in those areas to that color. A downside to this approach is that it won’t work perfectly with different display aspect ratios, but if you’re only ever using a 16:9 display that would be mitigated.
Brightness function:
// Helper function to compute average brightness of an image.
getAverageBrightness: function(image, callback) {
var canvas = document.createElement("canvas");
var width = image.naturalWidth;
var height = image.naturalHeight;
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0, width, height);
try {
var imageData = context.getImageData(0, 0, width, height);
} catch (error) {
console.error("Error accessing image data:", error);
callback(255); // Assume bright background if error.
return;
}
var data = imageData.data;
var colorSum = 0;
var pixels = data.length / 4;
for (var i = 0; i < data.length; i += 4) {
var r = data[i];
var g = data[i + 1];
var b = data[i + 2];
// Calculate brightness using the luminance formula.
var brightness = 0.299 * r + 0.587 * g + 0.114 * b;
colorSum += brightness;
}
var averageBrightness = colorSum / pixels;
callback(averageBrightness);
},
Updated onImageLoaded function:
onImageLoaded: function(imageData, element) {
var self = this;
return () => {
self.resetLoadImageTimer();
element.className = `wallpaper ${self.config.crossfade ? "crossfade-image" : ""}`;
element.style.opacity = 1;
// Analyze the image brightness and adjust text color accordingly.
// This will update both the module's caption and a global CSS variable.
self.getAverageBrightness(element, function(brightness) {
var threshold = 128; // Adjust this threshold as needed.
var textColor = brightness > threshold ? "black" : "white";
self.title.style.color = textColor;
// Set a global CSS variable for dynamic text color.
document.documentElement.style.setProperty('--dynamic-text-color', textColor);
});
self.title.style.display = "none";
setTimeout(() => {
var caption = imageData.caption;
if (self.config.caption && caption) {
self.title.innerHTML = caption;
self.title.style.display = "initial";
}
if (self.imageElement !== null) {
self.content.removeChild(self.imageElement);
}
self.imageElement = self.nextImageElement;
self.nextImageElement = null;
}, self.config.crossfade ? 1000 : 0);
};
},