Manipulation of color of an html image - css

So I thought I could do a smart manipulation of the color of a random shaped PNG image, by actually having 4 images of the same shape, but in Red, Green, Blue and Black, then set then on top of each other and manipulate their opacities.
I tried using the formula channelOpacity = channelVal / 255 / 3;
Well, it's not really that easy, it turns out. Has anyone attempted similar things and what would be a solution? Thank you.

It's an interesting idea. However, opacity alone doesn't seem to accomplish your objective, because the order in which the PNGs are defined will affect the color of their combination.
For example, if you have a red PNG, a green PNG, then a blue PNG, all with opacity 0.33, you'll get something like this:
If you rearrange their order as green, red, then blue, you'll get this:
Green, blue, then red will give you this:
There may be a way to take the order into account in your calculations, which could make your idea really useful.
Here's a snippet that sets the opacity of stacked red, green, and blue circles, based on the normalized rgb hex values from a color picker. It does a decent job for colors that are primarily red, green, or blue, but it suffers from the issue I've described:
var colorPicker= document.getElementById('colorPicker');
colorPicker.oninput= function() {
var red = document.getElementById('red');
var green= document.getElementById('green');
var blue = document.getElementById('blue');
var r= parseInt(this.value.substr(1,2),16);
var g= parseInt(this.value.substr(3,2),16);
var b= parseInt(this.value.substr(5,2),16);
var factor = 1/(r+g+b);
red.style.opacity = r * factor;
green.style.opacity= g * factor;
blue.style.opacity = b * factor;
}
colorPicker.oninput();
img {
position: absolute;
}
Choose color: <input id="colorPicker" type="color" value="#ff0000">
<hr>
<img id="red" src="http://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Bullet-red.png/240px-Bullet-red.png">
<img id="green" src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bullet-green.png/240px-Bullet-green.png">
<img id="blue" src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Bullet-blue.png/240px-Bullet-blue.png">

I found a way to do it through canvas, here: permadi.com
Given that Firefox has also added support (v34) for the methods involved, this solution should work fine. Careful, there are a lot of mistakes in the code at the above link (I corrected them below), but the idea is awesome. Here's what it's about, roughly:
// image is an html image element
var myCanvas=document.createElement("canvas");
var myCanvasContext=myCanvas.getContext("2d");
var imgWidth=image.width;
var imgHeight=image.height;
// You'll get some string error if you fail to specify the dimensions
myCanvas.width= imgWidth;
myCanvas.height=imgHeight;
// alert(imgWidth);
myCanvasContext.drawImage(image,0,0);
// This function cannot be called if the image is not rom the same domain.
// You'll get security error if you do.
var imageData=myCanvasContext.getImageData(0,0, imgWidth, imgHeight);
// This loop gets every pixels on the image and
for (i=0; i<imageData.height; i++)
{
for (j=0; j<imageData.width; j++)
{
var index;
index=(i*4)*imageData.width+(j*4);
// then access your data and set it like this:
// imageData.data[index+0]; // red
// imageData.data[index+0]; // green
// imageData.data[index+0]; // ... till alpha
}
}
myCanvasContext.putImageData(imageData,0,0,0,0, imageData.width, imageData.height);
return myCanvas.toDataURL();

Related

How would I make a color relative to images in the background?

For example, if you go to Twitter and click on an image, you can see they have a nice color that is close to what you see on the image. I tried looking up ways to achieve this as well as trying to figure it out on my own but no luck. I'm not sure if there's a color: relative property or not.
if you want to use the a colour that exists in your image and set it as a background colour you need to use the canvas element in the following manner:
HTML (this is your image)
<img src="multicolour.jpg" id="mainImage">
JS
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let color = context.getImageData(randomX, randomY, 1, 1).data
// use the data to dynamically add a background color extracted from your image
body[0].style.backgroundColor = `rgb(${color[0]},${color[1]},${color[2]})`
}
here is a gif of the code working... hopefully this helps
UPDATE
Here is the code to select two random points and create a css3 background gradient
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let colorOne = context.getImageData(randomX, randomY, 1, 1).data
// THE SAME TO OBTAIN ANOTHER pixel data
let randomX2 = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY2 = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
let colorTwo = context.getImageData(randomX2, randomY2, 1, 1).data
// use the data to dynamically add a background color extracted from your image
//body[0].style.backgroundColor = `rgb(${allColors[0]},${allColors[1]},${allColors[2]})`
body[0].style.backgroundImage = `linear-gradient(to right, rgb(${colorOne[0]},${colorOne[1]},${colorOne[2]}),rgb(${colorTwo[0]},${colorTwo[1]},${colorTwo[2]}))`;
}
The following are your options.
1. Use an svg.
As far as I know there's no way to have javascript figure out what color is being used in a png and set it as a background color. But you can work the other way around. You can have javascript set the background color and an svg image to be the same color.
See this stackoverflow answer to learn more about modifying svgs with javascript.
2. Use a custom font.
There are fonts out there that provide a bunch of icons instead of letters, you can also create your own font if you feel so inclined to do so. With css you just have to set the font-color of that icon to be the same as the background-color of your other element.
Font Awesome provides a bunch of useful custom icons. If the image you need to use happens to be similar to one of theirs, you can just go with them.
3. Use canvas
If you really want to spend the time to code it up you can use a html <canvas/> element and put the image into it. From there you can inspect certain details about the image like its color, then apply that color to other elements. I won't go into too much detail about using this method as it seems like it's probably overkill for what you're trying to do, but you can read up more about from this stackoverflow answer.
4. Just live with it.
Not a fun solution, but this is usually the option I go with. You simply have to hard-code the color of the image into your css and live with it. If you ever need to modify the color of the image, you have to remember to update your css also.

referencing global variables in a continuous function (p5.js)

it's been years since I coded anything, and now I need to pick up p5.js. As practice I was trying to make a simple drawing program - I want my program to draw in black by default, and switch the color to red when I click on the red rectangle in the corner of the screen. I had the following very sloppy code (I know the mouse-press doesn't exactly line up with the red rectangle, the 'drawing' mechanism isn't the best, etc. I'm just messing around with it atm)
function setup() {
createCanvas(600, 600);
fill ('red');
rect(570,20,5,5);
//creates red rectangle at top right corner of screen
}
var color = 0;
function mousePressed(){
if ( mouseX > 570) {
if( mouseY > 20){
color = 4;
ellipse (10,20,50,50);
}
}
}
function draw() {
stroke(color);
if (mouseIsPressed) {
ellipse(mouseX, mouseY, 1, 1)
//creates colored dot when mouse is pressed
}
}
function keyTyped(){
if (key === 'c'){
clear();
}
}
If I don't use the 'color' variable and instead just set the stroke to 0, I can draw in black well enough. And the mousePressed function seems to work - when I press the rectangle, it draws the ellipse that I put in to test. However, I can't seem to reference var 'color' in my draw function - it's probably a silly problem, but I admit to being stumped! What am I doing wrong?
You have to be careful when naming variables. Specifically, you shouldn't name them the same thing as existing functions!
From the Processing.js help articles:
One of the powerful features of JavaScript is its dynamic, typeless nature. Where typed languages like Java, and therefore Processing, can reuse names without fear of ambiguity (e.g., method overloading), Processing.js cannot. Without getting into the inner-workings of JavaScript, the best advice for Processing developers is to not use function/class/etc. names from Processing as variable names. For example, a variable named line might seem reasonable, but it will cause issues with the similarly named line() function built-into Processing and Processing.js.
Processing.js is JavaScript, so functions can be stored in variables. For example, the color variable is the color() function! So when you create your own color variable, you're overwriting that, so you lose the ability to call the color() function.
The simplest fix is to just change the name of your color variable to something like myColor.

How can I do an SVG Path drawing animation when the stroke has a dasharray?

Looking to animate the below SVG, which I have got working initially. However, I want it to 'draw' the second SVG in the opposite direction, WITH the dots i've defined.
Is there any way I can do this? Effectively drawing my shape from left to right with the dots.
Codepen: http://codepen.io/anon/pen/gFcAz
The normal dash offset animation trick really only works with solid lines.
This is the closest I managed to get using CSS animations.
http://jsfiddle.net/L4zCY/
Unfortunately the dashes crawl because you have no control over the step rate of the stroke-dashoffset. If you could make it step by 10 at a time, the dashes wouldn't move.
So I think the only way around it is to use Javascript.
var path = document.querySelectorAll("svg path").item(0);
animateDashedPath(path);
/*
* Animates the given path element.
* Assumes the path has a "5 5" dash array.
*/
function animateDashedPath(path)
{
var pathLength = path.getTotalLength();
var animationDuration = 2000;
var numSteps = Math.round(pathLength / (5+5) + 1);
var stepDuration = animationDuration / numSteps;
// Build the dash array so we don't have to do it manually
var dasharray = [];
while (numSteps-- > 0) {
dasharray.push(5);
dasharray.push(5);
}
dasharray.push(pathLength);
// Animation start conditions
path.setAttribute("stroke-dasharray", dasharray.join(" "));
path.setAttribute("stroke-dashoffset", -pathLength);
// We use an interval timer to do each step of the animation
var interval = setInterval(dashanim, stepDuration);
function dashanim() {
pathLength -= (5+5);
path.setAttribute("stroke-dashoffset", -pathLength);
if (pathLength <= 0) {
clearInterval(interval);
}
}
}
Demo here
Update
It looks like there is an issue with in FF. If you create the "right" number of dashes for the path length, it doesn't quite reach the end of the path. You need to add extra.
A version of the demo that works properly on FF is here

Programmatically fading in an image in PlayN

I'm working on a game using PlayN, and there's a bit where I would like to take an image (which is currently in PNG format, with 8-bit alpha already) and I would like to multiply the image by an additional alpha factor, based on a value from my code.
Specifically, I have a picture of a face that currently lives in an ImageLayer, and the effect that I would like would be to have something like this:
void init() {
faceImage = assetManager().getImage("images/face.png");
graphics().rootLayer().add(faceImage);
}
void update(float deltaMilliseconds) {
// start at fully transparent, fade to fully opaque
float transparency = calcTransparency(deltaMilliseconds);
faceImage.setTransparency(transparency);
}
I expect that there's some way to do some trickiness with GroupLayers and blend modes, perhaps blending the image with a CanvasLayer painted with a solid white rectangle with transparency controlled by my code, but it's not obvious to me if that's the best way to achieve what seems like a pretty common effect.
If you just want to fade the image in from fully-transparent to fully-opaque, then just do the following:
ImageLayer faceLayer;
void init() {
Image faceImage = assetManager().getImage("images/face.png");
faceLayer = graphics().createImageLayer(faceImage);
graphics().rootLayer().add(faceLayer);
}
void update(float delta) {
float alpha = calcAlpha(delta);
faceLayer.setAlpha(alpha);
}
Where alpha ranges from 0 (fully transparent) to 1 (fully opaque).

Photoshop PhotoFilter pixel Math

Has anyone used the photo filter in Photoshop? Edit > Adjustments > Photo Filter...
It produces a really nice image tint that I've been unable to reproduce with blending modes. Has anyone got any idea of the pixel maths behind this filter? - So I can build a shader based on it.
It seems to basically be a luminosity preserving colour tint.
Has variables: Color, Amount and Preserve Luminosity.
Any ideas?
Filters (in light) are multiplicative, as in:
red_filter = ( 1 , 0 , 0 ) * color
I don't think any blend-modes exist for it, since any transparent overlay with that system would darken the image to some degree.
It's incredibly simple, but if anyone wants the hlsl code for this:
// Photoshop PhotoFilter style effect.
// Input filter color.
float4 FilterColor;
// Implicit texture sampler.
sampler TextureSampler : register(s0);
float4 PhotoFilter(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(TextureSampler, texCoord) * FilterColor;
}
technique GeneralEffect
{
pass Pass1
{
PixelShader = compile ps_2_0 PhotoFilter();
}
}

Resources