Skip to content

Instantly share code, notes, and snippets.

@paulirish
Created April 21, 2010 00:08
Show Gist options
  • Save paulirish/373253 to your computer and use it in GitHub Desktop.
Save paulirish/373253 to your computer and use it in GitHub Desktop.
jquery invert
// jquery invert plugin
// by paul irish
// some (bad) code from this css color inverter
// http://plugins.jquery.com/project/invert-color
// some better code via Opera to inverse images via canvas
// http://dev.opera.com/articles/view/html-5-canvas-the-basics/#insertingimages
// and some imagesLoaded stuff from me
// http://gist.github.com/268257
// the code is still pretty shit.
// needs better hex -> rgb conversion..
// it could use color caching and image caching and also some perf-y skip elements type stuff.
(function ($) {
$.fn.invert = function () {
$(this).find('*').andSelf().each(function () {
var t = $(this);
change_part('color', t);
change_part('backgroundColor', t);
$.each(['right', 'bottom', 'left', 'top'], function (i, val) {
change_part('border-' + val + '-color', t);
});
changeImage(t);
});
return this;
};
function change_part(prop, t) {
var c = to_rgb(t.css(prop));
if (c != 'transparent' && c.substring(0, 4) != 'rgba') {
var rgb = /rgb\((.+),(.+),(.+)\)/.exec(c);
t.css(prop, 'rgb(' + (255 - rgb[1]) + ',' + (255 - rgb[2]) + ',' + (255 - rgb[3]) + ')');
}
}
function to_rgb(c) {
if (c.substring(0, 3) == 'rgb' || c == 'transparent') return c;
if (c.substring(0, 1) == '#') {
if (c.length == 4) {
c = '#' + c.substring(1, 2) + c.substring(1, 2) + c.substring(2, 3) + c.substring(2, 3) + c.substring(3, 4) + c.substring(3, 4)
}
return 'rgb(' + parseInt(c.substring(1, 3), 16) + ',' + parseInt(c.substring(3, 5), 16) + ',' + parseInt(c.substring(5, 7), 16) + ')';
}
var name = ['black', 'white', 'red', 'yellow', 'gray', 'blue', 'green', 'lime', 'fuchsia', 'aqua', 'maroon', 'navy', 'olive', 'purple', 'silver', 'teal'],
replace = ['(0, 0, 0)', '(255, 255, 255)', '(255, 0, 0)', '(255, 255, 0)', '(128, 128, 128)', '(0, 0, 255)', '(0,128,0)', '(0, 255, 0)', '(255, 0, 255)', '(0, 255, 255)', '(128, 0, 0)', '(0, 0, 128)', '(128, 128, 0)', '(128, 0, 128)', '(192, 192, 192)', '(0, 128, 128)'];
c = replace[$.inArray(c, name)] || c;
return 'rgb' + c;
}
function changeImage(t) {
// only operate on img tags and backgroundImages in dataurl or url form.
if (!(t.is('img') || /^(data|url)/.test(t.css('backgroundImage')))) return;
var img = new Image();
$(img).bind('load', function () {
var elem = document.createElement('canvas');
elem.width = img.width;
elem.height = img.height;
var context = elem.getContext('2d'),
x = 0,
y = 0,
result;
try {
// Draw the image on canvas.
context.drawImage(img, x, y);
// Get the pixels.
var imgd = context.getImageData(x, y, img.width, img.height);
var pix = imgd.data;
// Loop over each pixel and invert the color.
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i] = 255 - pix[i]; // red
pix[i + 1] = 255 - pix[i + 1]; // green
pix[i + 2] = 255 - pix[i + 2]; // blue
// i+3 is alpha (the fourth element)
}
// Draw the ImageData object.
context.putImageData(imgd, x, y);
result = elem.toDataURL();
}
catch (e) {
// image is on a different domain.
}
if (t.is('img')) t.attr('src', result)
else t.css('backgroundImage', 'url(' + result + ')');
}).each(function () {
// cached images don't fire load sometimes, so we reset src.
if (this.complete || this.complete === undefined) {
var src = this.src;
this.src = '#';
this.src = src;
}
});
var match = t.css('backgroundImage').match(/url\((.*?)\)/),
bg = match && match[1];
// img src, url bg, datauri background.
img.src = t[0].src || bg || t.css('backgroundImage');
}
})(jQuery);
@paulirish
Copy link
Author

Someone asked me if this is the best way to invert a page... Here's how i think the lay of the land is today...


In newer webkit browsers you have CSS filters so you can do:

body { -webkit-filter: invert(1); }

In oldIE you can hypothetically use the DXImageTransform.Microsoft.Invert() filter.. Though my quick attempt to get that going fails, but I'm sure there's a way..

Lea's invert approach is slick and probably better than my css/canvas iteration...

So that'd leave a robust and fast invert function as:

  • IE9+: Lea's invert outline
  • old IE: legacy IE filters
  • Opera: Lea's invert outline
  • New Webkit: -webkit-filter: invert(1);
  • Old Webkit: Invert all css colors, to invert Images. (this gist)
  • Firefox: SVG filters applied to HTML content http://dbaron.org/log/20110430-invert-colors

And hopefully as more browsers add support for CSS filters, they can shift to that approach.

@molokoloco
Copy link

Thanks you, i was looking for a solution to invert Soundcloud waveform images
Here a playable demo optimised for images
http://jsfiddle.net/molokoloco/WCL5w/ :)

@brianblakely
Copy link

I had success with this in IE7/8

body {
    filter: progid:DXImageTransform.Microsoft.BasicImage(invert=1);
    zoom: 1;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment