Generating gradients from a hexcode or RGB in PHP/jQuery? - php

I'm trying to figure out how to write a function that programmatically retrieves a background-color css attribute and creates two outputs (one slightly darker than the background-color, one slightly lighter).
The idea is being able to generate a very basic linear gradient from a single color selection.
Anyone have any ideas?

To scale a color correctly, you have to multiply each RGB value by a proportion. E.g., if your color is #00417b and you want a color that is 125% lighter color then you have to do this:
var dark = {r: 0, g: 65, b: 123};
var light = {r: Math.round(Math.min(dark[r]*1.25, 255)),
g: Math.round(Math.min(dark[g]*1.25, 255)),
b: Math.round(Math.min(dark[b]*1.25, 255))};
Compare the result for yourself: dark is #00417b, and light is #00519A, although it's perfectly valid CSS to describe them as rgb(0, 65, 123) and rgb(0, 81, 154) and probably easier too. By scaling colors in this way they will appear to be at the same level of saturation, something that simply adding or subtracting numbers will not achieve.
Be aware that since values are clamped at [0, 255], if you keep shifting colors, then feeding them back into this process, you can destroy information about the proportion of red, green and blue in the source color. For this reason, keep the original color saved and try to use that as your input each time.
Since your question asked specifically about gradients though, this is how you would go between two color values:
// Suppose you have a container which is X pixels high and you want to insert a 1-pixel tall
// element at each pixel, going vertically
var min = Math.min;
var max = Math.max;
var round = Math.round;
function get_color_for_height(startColor, endColor, height, row) {
var scale = row/height;
var r = startColor[red] + scale*(endColor[red] - startColor[red]);
var b = startColor[blue] + scale*(endColor[blue] - startColor[blue]);
var g = startColor[green] + scale*(endColor[green] - startColor[green]);
return {
r: round(min(255, max(0, r))),
g: round(min(255, max(0, g))),
b: round(min(255, max(0, b)))
}
}
// some psuedo-code using an imaginary framework
for(var h = 0; h < height; h++) {
var div = new Element('div');
div.height = 1;
div.backgroundColor = get_color_for_height(start, end, height, h);
container.insert('top', div);
}

To generate a darker or lighter vairant, a simple possibility is just to add or subtract a fixed number to all three componenents, capping it at 0 and 255/0xFF.

Related

Write Text/Values On 360 degree Circle

I am working on a wheel chart design, I need help in positioning the text on the 360 wheel.
The wheel have 12 sections, each one of 30 degree. The text's offset from the circle outer line should be equal (or similar at least). like in the image below I have mocked up what I need in final result.
So far, What I have tried is splitting each section into separate variable e.g.
$section1_startX = 50;
$section1_endX = 70;
$section1_startY = 310;
$section1_endY = 480;
and then to place text
imagettftext($im, 15, 0, $section1_startX, $section1_startY, $black, $font, "05");
but this is to find/calculate pixels of each line I need to place.
I am sure there is better, dynamic and smart way to put the text at x,y positions based on its values in 360 circle.
can you please help me regarding?
Hi I think you want to find a Point on a given circle with a given degree. Here is a function for calculating point on a circle. I think you can convert this to any other language easily.
public static PointF PointOnCircle(float radius, float angleInDegrees, Point origin)
{
//radius -> Radius of Circle & Origin -> Circle Centre.
// Convert from degrees to radians via multiplication by PI/180
float x = (float)(radius * Math.Cos(angleInDegrees * Math.PI / 180F)) + origin.X;
float y = (float)(radius * Math.Sin(angleInDegrees * Math.PI / 180F)) + origin.Y;
return new PointF(x, y);
}

CSS or PHP? color that is 80% of original but without "transparency"?

this might be a tough question.
I have a php function that returns a color value in rgba() with an argument $alpha.
function colorWheel($alpha) {
"rgba(170, 135, 178, ".$alpha.")"
…
}
So when calling …
.title { color: <?php echo colorWheel(.8); ?>; }
… I get rgba(170, 135, 178, .8);
The problem I have with this is that the color is "transparent" and shows "overlays".
However what I really like to have is just 80% of the color value!
Without any transparent overlays.
The question is now how to solve this?
Any creative ideas how to do that? I don't need to use rgba() it's just the easiest thing that came to my mind. Is there a CSS way not to blend overlaying shapes that have an alpha value?
Or is there a php solution to calculate a the 80% version of rgb(170, 135, 178)?
It is important that this calculation works dynamically with the function because there are more colors in the function - this is a follow-up question to "How to return a color-value based a date and random?"!
Thank you in advance.
The Question is what your definition of "80% of the color" actually is.
CSS has 2 color spaces available at the moment: RGB and HSL (which is actually supported pretty well).
You could do the following RGB calculation:
function colorWheel($alpha) {
'rgba('.$r*$alpha.','.$g*$alpha.','.$b*$alpha.', 1)';
…
}
Or you could take HSL and just reduce the luminance (and or Saturation) channel by 20%. The HSL colorspace is more intuitive when doing things like making colors darker/brighter.
function colorWheel($alpha) {
"hsla($h,$s,".$l*$alpha.",1)";
// or
// ("hsla($h, "+$s*$alpha+", $l, 1)";)
…
}
These all yield (slightly) different results.
The colorspaces can be converted into each other via some not too complicated formulas. Perhaps you should take a look at a random colorpicker(e.g. this one or that one) and then decide, which way of calculation suits you best.
that should do it:
function colorWheel($alpha) {
$r = round(170 * $alpha);
$g = round(135 * $alpha);
$b = round(178 * $alpha);
"rgba($r, $g, $b, 1)";
…
}
well, that makes the color darker, if you want to make it lighter you have to put alpha to a value > 1, and also check if r,g or b goes over 255 and set it to 255 if it does
To simulate color with opacity you also need background color. Lets say, that R,G,B are background color components, and r,g,b are you color components.
If you want to simulate opacity color on specific background, you should take corresponding values of same canal and add them with specific weights:
r = r*alpha + R*(1-alpha)
g = g*alpha + G*(1-alpha)
b = b*alpha + B*(1-alpha)
Lets take simple example. You want to get alpha = 0.8 on color rgb(r,g,b) = rgb(255,0,0) (red) on background rgb(R,G,B) = rgb(255,255,255) (white). That means, you need sum 80% your color + 20% BG:
r = 255*0.8 + 255*0.2 = 255
g = 0*0.8 + 255*0.2 = 51
b = 0*0.8 + 255*0.2 = 51

Change/Overlay color on single-colored PNG image with transparent background?

What I would like to be able to do is dynamically change a solid single-colored png to another color simply by inputting the desired color code without losing the transparent background. The implementations I've seen tend to be a bit sloppy, so I was wondering if anyone can give me advice on how they would implement it.
I'd be most comfortable with a PHP solution but Python works too, hell I'll even take a good canvas solution. Any advice/examples regarding this would be very much appreciated, thanks guys.
Here's a simple canvas implementation:
colorize = function(image, r, g, b) {
var newImg = $('<canvas>')[0];
newImg.width = image.width;
newImg.height = image.height;
var newCtx = newImg.getContext('2d');
newCtx.drawImage(image, 0, 0);
var imageData = newCtx.getImageData(0, 0, image.width, image.height);
data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i+0] = r;
data[i+1] = g;
data[i+2] = b;
}
newCtx.putImageData(imageData, 0, 0);
return newImg;
};
JSFiddle: http://jsfiddle.net/bK7P9/6/
Ordinarily I like to work in the RGB color space, but this is a case where HLS works very well. The conversion in Python is simple, by replacing the H and S and leaving L the same.
import colorsys
from PIL import Image
def recolor(im, r, g, b):
h, l, s = colorsys.rgb_to_hls(r/255.0, g/255.0, b/255.0)
result = im.copy()
pix = result.load()
for y in range(result.size[1]):
for x in range(result.size[0]):
r2, g2, b2, a = pix[x, y]
h2, l2, s2 = colorsys.rgb_to_hls(r2/255.0, g2/255.0, b2/255.0)
r3, g3, b3 = colorsys.hls_to_rgb(h, l2, s)
pix[x, y] = (int(r3*255.99), int(g3*255.99), int(b3*255.99), a)
return result
recolor(im_flag, 255, 0, 0).save(r'c:\temp\red_flag.png')
You can do this using PIL and numpy in Python. Assuming we have a method NewSolidImage (which we'll define below), we can turn an image into an array of pixels, use the method to convert the pixels and then save to a new file:
import numpy
from PIL import Image
def CreateNewImage(current_filename, new_filename, new_color):
image = Image.open(current_filename)
image_values = numpy.array(image)
new_image_values = NewSolidImage(image_values, new_color)
new_image = Image.fromarray(new_image_values)
new_image.save(new_filename)
Now to define this method. We simply take an array, make sure it is the shape that we expect and then on pixels that aren't 100% transparent, we set the red, green, blue values to those of the solid passed in.
def NewSolidImage(rgba_array, new_color):
new_r, new_g, new_b = new_color
rows, cols, rgba_size = rgba_array.shape
if rgba_size != 4:
raise ValueError('Bad size')
for row in range(rows):
for col in range(cols):
pixel = rgba_array[row][col]
transparency = pixel[3]
if transparency != 0:
new_pixel = pixel.copy()
new_pixel[0] = new_r
new_pixel[1] = new_g
new_pixel[2] = new_b
rgba_array[row][col] = new_pixel
return rgba_array

Converting int to RGB. Visualization in PHP and HTML/CSS

I'm trying to visualize a data on a grid with cell values actually represented by color. Red means high and blue means low. I was so naive in thinking that PHP's dechex() will help me by simply getting the hexadecimal equivalent of the int and using it as background-color in CSS (I did apply the necessary padding of zeros for small values).
But it doesn't quite get me what I want. Is there an algorithm that will let me visualize this properly? Red means high, blue means low.
My current code is this:
<?php
$dec = (int) $map[$y][$x]["total_score"];
$hex = dechex($dec);
$color = ($dec <= 65535) ? (($dec) ? "00$hex" : "ffffff") :
(($dec <= 1048575) ? ("0$hex") : $hex);
?>
Notice what it does:
ff0000 in decimal is smaller than ff00ff but on color, the first will show red and the latter violet. I want red to represent very high decimals and blue very low decimals.
I think RGB is not the very best color model here. I'd go with HSL - supported by modern browsers: color: hsl(0.5, 0.5, 0.5) and easily to convert to RGB.
HSL let's you define saturation and lightness of the color and the color itself quite easily. Blue is 240 deg, red is 360 deg so all you have to do is to map "low" to 240, "high" to 360 and all mid-value to 240-360 range.
Replace Red with Green and Remove Green by masking with 0xFF00FF in order to keep Red and Blue only.
$color = $your_decimal_number_you_want_to_colorize; // for example $color is 0x00F777
$color = $color << 8; // color is 0xF77700
$color = $color + ($color & 0x00FF00); // color is 0xF77777
$color = $color & 0xFF00FF; // color is 0xF70077
Using the code above, if $a > $b then $a will be more red than $b.

Detecting blank generated images with php?

How would I be able to detect that an image is blank (only of a single, arbitrary color or, with a gif, frames of random arbitrary colors) using PHP and/or imagemagick?
I think this is what I'm going to try:
http://www.php.net/manual/en/function.imagecolorat.php#97957
You can check the image inside of PHP using imagecolorat (this may be slow, but it works):
function isPngValidButBlank($filename) {
$img = imagecreatefrompng($filename);
if(!$img)
return false;
$width = imagesx($img);
$height = imagesy($img);
if(!$width || !$height)
return false;
$firstcolor = imagecolorat($img, 0, 0);
for($i = 0; $i < $width; $i++) {
for($j = 0; $j < $height; $j++) {
$color = imagecolorat($img, $i, $j);
if($color != $firstcolor)
return false;
}
}
return true;
}
http://www.php.net/manual/en/function.imagecolorstotal.php gives you the amount of colors in an image. Hmm, in my demo it doesn't seem to work, sorry :( an image i created (fully red, 20x20 pixels) gives 0 colors for PNG and 3 colors for GIF.
Ok: http://www.dynamicdrive.com/forums/showpost.php?p=161187&postcount=2 look at the 2nd piece of code. Tested here: http://www.pendemo.nl/totalcolors.php
Kevin's solution can be sped up using random sampling. If you have some idea of the percentage of pixels that should be different from the background (assuming you aren't dealing with lots of images with only 1 different pixel), you can use the Poisson distribution:
probability of finding a nonblank pixel = 1 - e^(-n*p)
where n is the number of samples to try, and p is the percentage of pixels expected to be nonblank. Solve for n to get the appropriate number of samples to try:
n = -log(1 - x) / p
where x is the desired probability and log is natural log. For example, if you are reasonably sure that 0.1% of the image should be nonblank, and you want to have a 99.99% chance of finding at least one nonblank pixel,
n = -log(1-.9999)/.001 = 9210 samples needed.
Much faster than checking every pixel. To be 100% sure, you can always go back and check all of them if the sampling doesn't find any.
For anyone using Imagick to try and achieve this, the getImageColors() method did the trick.
https://www.php.net/manual/en/imagick.getimagecolors.php
$img = new Imagick();
$img->readImage($image);
$colors = $img->getImageColors();
if(!$colors > 1) {
return false;
}
Get the standard-deviation from the verbose statistics for each tile. If the standard deviation is 0, then the image is one color.
Supposedly, 'number of colors' will also do this; would be 1.
Use the -format option: http://www.imagemagick.org/script/escape.php

Categories