22

I am working on a product that outputs images from users and the image information is overlayed on top of the aforementioned images. As you might imagine, the images require different text colors due to lightness/darkness. Is there a way to achieve this with JavaScript?

EDIT: I found a similar question to mine and there was a solution given in a jsfiddle (http://jsfiddle.net/xLF38/818). I am using jQuery for my site though. How would I convert the vanilla JavaScript to jQuery?

var rgb = getAverageRGB(document.getElementById('i'));
document.body.style.backgroundColor = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';

function getAverageRGB(imgEl) {

    var blockSize = 5, // only visit every 5 pixels
        defaultRGB = {
            r: 0,
            g: 0,
            b: 0
        }, // for non-supporting envs
        canvas = document.createElement('canvas'),
        context = canvas.getContext && canvas.getContext('2d'),
        data, width, height,
        i = -4,
        length,
        rgb = {
            r: 0,
            g: 0,
            b: 0
        },
        count = 0;

    if (!context) {
        return defaultRGB;
    }

    height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
    width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

    context.drawImage(imgEl, 0, 0);

    try {
        data = context.getImageData(0, 0, width, height);
    } catch (e) {
        /* security error, img on diff domain */
        alert('x');
        return defaultRGB;
    }

    length = data.data.length;

    while ((i += blockSize * 4) < length) {
        ++count;
        rgb.r += data.data[i];
        rgb.g += data.data[i + 1];
        rgb.b += data.data[i + 2];
    }

    // ~~ used to floor values
    rgb.r = ~~ (rgb.r / count);
    rgb.g = ~~ (rgb.g / count);
    rgb.b = ~~ (rgb.b / count);

    return rgb;

}
NetOperator Wibby
  • 1,354
  • 5
  • 22
  • 44

3 Answers3

11

I finally found something to do precisely what I want it to do! Enter Brian Gonzalez's jquery.adaptive-backgrounds.js. Check this out:

$parent.css({
        // backgroundColor: data.color
        color: data.color
});

I just commented out the backgroundColor rule and made a new one for color. For white text, a text-shadow like:

text-shadow: 0 0 1px rgba($black, 0.3); // using Sass

should be enough. Thank you to everyone for your answers!

NetOperator Wibby
  • 1,354
  • 5
  • 22
  • 44
6

This is possible using the canvas element. You would have to create a canvas element, draw the image element into the canvas, get the canvas's image data, look at the portion where the text is, convert those values to grayscale, average them, then compare them with a halfway point. Some example code:

var img = document.getElementById('myImage');
var c = document.createElement('canvas');
var ctx = c.getContext('2d');
var w = img.width, h = img.height;
c.width = w; c.height = h;
ctx.drawImage(img, 0, 0);
var data = ctx.getImageData(0, 0, w, h).data;
var brightness = 0;
var sX = 0, sY = 0, eX = w, eY = h;
var start = (w * sY + sX) * 4, end = (w * eY + eX) * 4;
for (var i = start, n = end; i < n; i += 4) {
      var r = data[i],
          g = data[i + 1],
          b = data[i + 2];
      brightness += 0.34 * r + 0.5 * g + 0.16 * b;
      if (brightness !== 0) brightness /= 2;
}
if (brightness > 0.5) var textColor = "#FFFFFF";
else var textColor = "#000000";

I haven't tested this code, though it should work. Make sure to change the sX, sY, eX, eY values to only the area where your text is, otherwise you will get unsatisfactory results (it will still work). Good luck!

EDIT: You will not have to display your image in any special way. Just make sure that the color of the overlay text is the variable textColor.

rvighne
  • 20,755
  • 11
  • 51
  • 73
-2

you could check the background-image attribute with jQuery then adjust the text color dynamically.

var x = $(body).attr("background-image");
switch(x)
{
  case "something.png":
      // set color here
      break;
}
jappple
  • 25
  • 3
  • 1
    Hi user2501897, this looks good for a small project, but how would this work dynamically? – NetOperator Wibby Jun 19 '13 at 16:06
  • The image content/color is unknown so this is of no use. – Wesley Murch Jun 19 '13 at 16:28
  • Not dynamic in the sense it would pick up on the appropriate color from the image - but using the above code on form load (or at least after the background image is assigned) you could just declare when the image name is x the text color should be y. – jappple Jun 19 '13 at 17:03
  • By dynamic, I mean that I wouldn't know what the image looks like ahead of time. This is user-generated content, therefore I would not know which color to set the text as. – NetOperator Wibby Jun 19 '13 at 17:52
  • This suggestion, as provided, does not achieve the desired results. @rvighne has provided a proposed solution that addresses the question. – Mike Kormendy Nov 13 '13 at 00:56